R/3-UserMinimaxFunctions.R

Defines functions minimax.update update.minimax sens.minimax.control print.sensminimax print.minimax plot.minimax locallycomp multiple robust locally minimax

Documented in locally locallycomp minimax multiple plot.minimax print.minimax print.sensminimax robust sens.minimax.control update.minimax

######################################################################################################*
######################################################################################################*
#' @title Minimax and Standardized Maximin D-Optimal Designs
#' @description
#'
#'  Finds minimax and standardized maximin D-optimal designs for linear and nonlinear models.
#'  It should be used when the user assumes the unknown parameters belong to a parameter region
#'  \eqn{\Theta}, which is called ``region of uncertainty'',  and the
#'    purpose is to protect the experiment from the worst case scenario
#'   over \eqn{\Theta}.
#'
#'
#'@param formula A linear or nonlinear model \code{\link[stats]{formula}}.
#' A symbolic description of the model consists of predictors and the unknown model parameters.
#' Will be coerced to a \code{\link[stats]{formula}} if necessary.
#'@param predvars A vector of characters. Denotes the predictors in the \code{\link[stats]{formula}}.
#'@param parvars A vector of characters. Denotes the unknown parameters in the \code{\link[stats]{formula}}.
#' @param family A description of the response distribution and the link function to be used in the model.
#'  This can be a family function, a call to a family function or a character string naming the family.
#'   Every family function has a link argument allowing to specify the link function to be applied on the response variable.
#'    If not specified, default links are used. For details see \code{\link[stats]{family}}.
#'     By default, a linear gaussian model \code{gaussian()} is applied.
#' @param lx Vector of lower bounds for the predictors. Should be in the same order as \code{predvars}.
#' @param ux Vector of upper bounds for the predictors. Should be in the same order as \code{predvars}.
#' @param lp Vector of lower bounds for the model parameters. Should be in the same order as \code{parvars} or \code{param} in the argument \code{fimfunc}.
#' @param up Vector of upper bounds for the model parameters. Should be in the same order as \code{parvars} or \code{param} in the argument \code{fimfunc}.
#' When a parameter is known (has a fixed value), its associated lower and upper bound values  in \code{lp} and \code{up}  must be set equal.
#' @param iter Maximum number of iterations.
#' @param k Number of design points. Must be at least equal to the number of model parameters to avoid singularity of the FIM.
#' @param n.grid Only required when the parameter space is
#' going to be discretized.
#' The total number of grid points from the parameter space is \code{n.grid^p}.
#'  When \code{n.grid > 0}, optimal design protects the experimenter against the worst case scenario only over the grid points, and not over the continuous parameter space.
#'   The resulting designs may not be globally optimal.
#'   In some literature, this type of designs has been used as a compromise to
#'   the minimax type designs to avoid continuous optimization problem over
#'    the parameter space and simplify the minimax design problems.
#'     Especially when the design criterion is convex with respect to the
#'   given parameter space at every given design from the design space,
#'    the obtained design may also be globally optimal (because the maximum of a convex function is attained on the bounds, and here, are included in the grid points).
#'   See 'Details' of \code{\link{minimax}}.
#' @param fimfunc A function. Returns the FIM as a \code{matrix}. Required when \code{formula} is missing. See 'Details' of \code{\link{minimax}}.
#' @param ICA.control ICA control parameters. For details, see \code{\link{ICA.control}}.
#' @param sens.minimax.control Control parameters to construct the answering set required for verify the general equivalence theorem and calculating the ELB. For details, see the function \code{\link{sens.minimax.control}}.
#' @param sens.control Control Parameters for Calculating the ELB. For details, see \code{\link{sens.control}}.
#' @param crt.minimax.control Control parameters to optimize the minimax or standardized maximin criterion at a given design over a \strong{continuous} parameter space (when \code{n.grid = 0}).
#'  For details, see the function \code{\link{crt.minimax.control}}.
#' @param standardized  Maximin standardized design? When \code{standardized = TRUE}, the argument \code{localdes} must be given.
#'  Defaults to \code{FALSE}. See 'Details' of \code{\link{minimax}}.
#' @param initial A matrix of the  initial design points and weights that will be inserted into the initial solutions (countries) of the algorithm.
#'  Every row is a design, i.e.  a concatenation of \code{x} and \code{w}. Will be coerced to a \code{matrix} if necessary.  See 'Details' of \code{\link{minimax}}.
#' @param localdes A function that takes the parameter values  as inputs and returns the design points and weights of the locally optimal design.
#'  Required when \code{standardized = "TRUE"}. See 'Details' of \code{\link{minimax}}.
#' @param npar Number of model parameters.  Used when \code{fimfunc} is given instead of \code{formula} to specify the number of model parameters.
#'   If not specified truly, the sensitivity (derivative) plot may be shifted below the y-axis. When \code{NULL} (default), it is set to \code{length(lp)}.
#' @param plot_3d Which package should be used to plot the sensitivity (derivative) function for two-dimensional design space. Defaults to \code{"lattice"}.
#' @param x A vector of candidate design (support) points.
#' When is not set to \code{NULL} (default),
#'  the algorithm only finds the optimal weights for the candidate points in  \code{x}.
#'    Should be set when the user has a finite number of candidate design points  and the purpose
#'    is to find the optimal weight for each of them (when zero, they will be excluded from the design).
#' For design points with more than one dimension, see 'Details' of \code{\link{sensminimax}}.
#' @param crtfunc (Optional) a function that specifies an arbitrary criterion. It must have especial arguments and output. See 'Details' of \code{\link{minimax}}.
#' @param sensfunc (Optional) a function that specifies the sensitivity function for \code{crtfunc}. See 'Details' of \code{\link{minimax}}.
#' @details
#'
#' Let \eqn{\Xi} be the space of all  approximate designs with
#'  \eqn{k} design points (support points) at \eqn{x_1, x_2, ...,  x_k}
#'  from  the design space \eqn{\chi} with
#'  corresponding weights  \eqn{w_1, . . . ,w_k}.
#'  Let \eqn{M(\xi, \theta)} be the Fisher information
#'   matrix (FIM) of a \eqn{k-}point design \eqn{\xi} and \eqn{\theta} be the vector of
#'    unknown parameters.
#'  A  minimax D-optimal design \eqn{\xi^*}{\xi*} minimizes over \eqn{\Xi}
#'   \deqn{\max_{\theta \in \Theta} -\log|M(\xi, \theta)|.}{
#'    max over \Theta -log|M(\xi, \theta)|.}
#'
#'  A standardized maximin D-optimal design \eqn{\xi^*}{\xi*} maximizes over \eqn{\Xi}
#'  \deqn{\inf_{\theta \in \Theta} \left[\left(\frac{|M(\xi, \theta)|}{|M(\xi_{\theta}, \theta)|}\right)^\frac{1}{p}\right],}{
#'   inf over \Theta {|M(\xi, \theta)| / |M(\xi_\theta, \theta)|}^p,}
#'   where \eqn{p} is the number of model parameters and \eqn{\xi_\theta} is the locally D-optimal design with respect to \eqn{\theta}.\cr
#'
#' A minimax criterion (cost function or objective function) is evaluated at each design (decision variables) by maximizing the criterion over the parameter space.
#' We call the optimization problem over the parameter space as \emph{inner optimization problem}.
#' Two different strategies may be
#'  applied to solve the inner problem at a given design (design points and weights):
#' \enumerate{
#' \item \strong{Continuous inner problem}: we optimize the criterion
#'  over a continuous parameter space using the function \code{\link[nloptr]{nloptr}}.
#' In this case, the tuning parameters can be regulated
#'  via the argument \code{\link{crt.minimax.control}}, when the most influential one
#'  is \strong{\code{maxeval}}.
#' \item  \strong{Discrete inner problem}: we map the parameter space to
#'  the grid points and optimize the criterion over a discrete parameter space.
#' In this case, the number of grid points can be regulated via \code{n.grid}.
#' This strategy is quite efficient (ans fast) when  the maxima most likely attain the vertices of the continuous parameter space at any given design.
#' The output design here protects the experiment from the worst scenario
#' over the grid points.
#' }
#'
#'
#' The \code{formula} is used to automatically create the Fisher information matrix (FIM)
#'  for a linear or nonlinear model provided that the distribution of the
#'   response variable belongs to the natural exponential family.
#' Function \code{minimax} also provides an
#'  option to assign a user-defined FIM directly via the argument  \code{fimfunc}.
#'  In this case, the
#' argument \code{fimfunc} takes a \code{function} that has three arguments as follows:
#'  \enumerate{
#'   \item \code{x} a vector of design points. For design points with more than one dimension,
#'    it is a concatenation of the design points, but dimension-wise.
#'    For example, let the model has three predictors   \eqn{(I, S, Z)}.
#'     Then,  a two-point design is of the format
#'    \eqn{\{\mbox{point1} = (I_1, S_1, Z_1), \mbox{point2} = (I_2, S_2, Z_2)\}}{{point1 = (I1, S1, Z1), point2 = (I2, S2, Z2)}}.
#'     and the argument \code{x} is equivalent to
#'     \code{x = c(I1, I2, S1, S2, Z1, Z2)}.
#'   \item \code{w} a vector that includes the design weights associated with \code{x}.
#'   \item \code{param} a vector of parameter values associated with \code{lp} and \code{up}.
#' }
#'  The output must be the Fisher information matrix with number of rows equal to \code{length(param)}. See 'Examples'.
#'
#'
#'
#'  Minimax optimal designs can have very different criterion values depending on the nominal set of parameter values.
#'  Accordingly, it is desirable to standardize the criterion and control for the potentially widely varying magnitude of the criterion (Dette, 1997).
#'  Evaluating a standardized maximin criterion requires knowing locally optimal designs.
#' We strongly advise setting \code{standardized = 'TRUE'} only when analytical solutions for the locally D-optimal designs is available.
#' In this case, for any initial estimate of the unknown parameters,
#' an analytical solution  for the locally optimal design, i.e, the support points \code{x}
#'  and the corresponding weights \code{w}, must be provided via the argument \code{localdes}.
#' Therefore, depending on how the model is specified, \code{localdes} is a \code{function} with the following arguments (input).
#' \itemize{
#' \item If \code{formula} is given (\code{!missing(formula)}):
#'     \itemize{
#'     \item The parameter names given by \code{parvars} in the same order.
#'
#'     }
#' \item If FIM is given via the argument \code{fimfunc} (\code{missing(formula)}):
#'    \itemize{
#'    \item \code{param}: A vector of the parameters equal to the argument \code{param} in \code{fimfunc}.
#'     }
#' }
#' This function must return a list with the components \code{x} and \code{w} (they match the same arguments in the function \code{fimfunc}).
#'   See 'Examples'.\cr
#'
#' The standardized D-criterion is equal to the  D-efficiency and it must be between 0 and 1.
#'  However, in practice, when running the algorithm,  it may be the case that
#'  the criterion takes a value larger than one.
#'   This may happen  because the user-function that is  given via \code{localdes} does not
#'   return the true (accurate) locally optimal designs for some
#'    requested initial estimates of the parameters  from \eqn{\Theta}.
#'  In this case, the function \code{minimax}
#' throw an error where the error message helps the user
#'  to debug her/his function.
#'
#'
#' Each row of \code{initial} is one design, i.e. a concatenation of values for design (support) points  and the associated design weights.
#' Let \code{x0} and \code{w0} be the vector of initial values with exactly the same length and order as \code{x} and \code{w} (the arguments of \code{fimfunc}).
#'  As an example, the first row  of the matrix \code{initial} is equal to \code{initial[1, ] = c(x0, w0)}.
#'   For models with more than one predictors, \code{x0} is a concatenation of the initial values for design points, but \strong{dimension-wise}.
#'   See the details of the argument \code{fimfunc}, above.
#'
#'  To verify the optimality of the output design by the general equivalence theorem,
#'  the user can either \code{plot} the results or set  \code{checkfreq} in \code{\link{ICA.control}}
#'  to \code{Inf}. In either way, the function \code{\link{sensminimax}} is called for verification.
#'   Note that  the function \code{\link{sensminimax}} always verifies the optimality of a design assuming a continues parameter space.
#' See 'Examples'.
#'
#'  \code{crtfunc} is a function that is used
#'  to specify a new criterion.
#'   Its arguments are:
#'   \itemize{
#'  \item design points \code{x} (as a \code{vector}).
#'  \item design weights \code{w} (as a \code{vector}).
#'  \item model parameters as follows.
#'      \itemize{
#'          \item If \code{formula} is specified:
#'                they should be the same parameter specified by \code{parvars}.
#'          \item If FIM is specified via the argument \code{fimfunc}:
#'              \code{param} that is a vector of the parameters in \code{fimfunc}.
#'               }
#'        \item \code{fimfunc} is a \code{function} that takes the other arguments of \code{crtfunc}
#'        and returns the computed Fisher information matrix as a \code{matrix}.
#'      }
#'    The \code{crtfunc} function must return the criterion value.
#'     \code{crtfunc}. It has one more argument than  \code{crtfunc},
#'      which is  \code{xi_x}. It denotes the design point of the degenerate design
#'      and  must be a vector with the same length as the number of  predictors.
#'     For more details, see 'Examples'.
#'
#'
#' @return
#'
#'  an object of class \code{minimax} that is a list including three sub-lists:
#' \describe{
#'   \item{\code{arg}}{A list of design and algorithm parameters.}
#'   \item{\code{evol}}{A list of length equal to the number of iterations that stores
#'    the information about the best design (design with least criterion value)
#'     of each iteration. \code{evol[[iter]]} contains:
#'     \tabular{lll}{
#'       \code{iter}                   \tab      \tab Iteration number.\cr
#'       \code{x}                      \tab      \tab Design points. \cr
#'       \code{w}                      \tab      \tab Design weights. \cr
#'       \code{min_cost}               \tab      \tab Value of the criterion for the best imperialist (design).  \cr
#'       \code{mean_cost}              \tab      \tab Mean of the criterion values of all the imperialists. \cr
#'       \code{sens}                   \tab      \tab An object of class \code{'sensminimax'}. See below. \cr
#'       \code{param}                  \tab      \tab Vector of parameters.\cr
#'     }
#'   }
#'
#'   \item{\code{empires}}{A list of all the  empires of the last iteration.}
#'   \item{\code{alg}}{A list with following information:
#'     \tabular{lll}{
#'       \code{nfeval}           \tab      \tab Number of function evaluations.  It does not count the function evaluations from checking the general equivalence theorem.\cr
#'       \code{nlocal}           \tab      \tab Number of successful local searches. \cr
#'       \code{nrevol}           \tab      \tab Number of successful revolutions. \cr
#'       \code{nimprove}         \tab      \tab Number of successful movements toward the imperialists in the assimilation step. \cr
#'       \code{convergence}      \tab      \tab Stopped by \code{'maxiter'} or \code{'equivalence'}?\cr
#'     }
#'   }
#'   \item{\code{method}}{A type of optimal designs used.}
#'   \item{\code{design}}{Design points and weights at the final iteration.}
#'   \item{\code{out}}{A data frame of design points, weights, value of the criterion for the best imperialist (min_cost), and Mean of the criterion values of all the imperialistsat each iteration (mean_cost).}
#' }
#'
#' The list \code{sens} contains information about the design verification by the general equivalence theorem. See \code{sensminimax} for more details.
#' It is given  every \code{ICA.control$checkfreq} iterations
#' and also the last iteration if   \code{ICA.control$checkfreq >= 0}. Otherwise, \code{NULL}.
#'
#'  \code{param} is a vector of parameters that is the global minimum of
#'   the minimax criterion or the global maximum of the standardized maximin criterion over the parameter space, given  the current \code{x}, \code{w}.
#'
#' @note
#' For larger parameter space or model with more number of unknown parameters,
#'  it is always important to increase the value of  \code{ncount} in \code{ICA.control}
#' and \code{optslist$maxeval} in \code{crt.minimax.control} to produce very accurate designs.
#'
#' Although standardized criteria have been preferred theoretically,
#' in practice, they should be applied only
#'   when  an analytical solution for
#'   the locally D-optimal designs is available for the model
#'   of interest.
#'    Otherwise, we encounter a three-level nested-optimization algorithm, which is very slow.
#'
#' @references
#' Atashpaz-Gargari, E, & Lucas, C (2007). Imperialist competitive algorithm: an algorithm for optimization inspired by imperialistic competition. In 2007 IEEE congress on evolutionary computation (pp. 4661-4667). IEEE.\cr
#' Dette, H. (1997). Designing experiments with respect to 'standardized' optimality criteria. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 59(1), 97-110. \cr
#' Masoudi E, Holling H, Wong WK (2017). Application of Imperialist Competitive Algorithm to Find Minimax and Standardized Maximin Optimal Designs. Computational Statistics and Data Analysis, 113, 330-345. <doi:10.1016/j.csda.2016.06.014>\cr
#' @example inst/examples/minimax_examples.R
#' @importFrom utils capture.output
#' @export
#' @seealso \code{\link{sensminimax}}
minimax <- function(formula, predvars, parvars, family = gaussian(),
                    lx, ux, lp, up, iter, k,
                    n.grid = 0,
                    fimfunc = NULL,
                    ICA.control = list(),
                    sens.control = list(),
                    sens.minimax.control = list(),
                    crt.minimax.control = list(),
                    standardized = FALSE,
                    initial = NULL,
                    localdes = NULL,
                    npar = length(lp),
                    plot_3d = c("lattice", "rgl"),
                    x = NULL,
                    crtfunc = NULL,
                    sensfunc = NULL){
  ### how to control ICA.control sens.minimax.control
  if (!is.numeric(n.grid) || n.grid < 0)
    stop("value of 'n.grid' must be >= 0")
  # if (!is.numeric(maxeval) || param_maxeval <= 0)
  #   stop("value of 'param_maxeval' must be > 0")
  if (!is.logical(standardized))
    stop("'standardized' must be logical")
  if (standardized)
    type <- "standardized" else
      type <- "minimax"

    # The number of the grid points used is length(lp)^n.grid

    #n.grid^length(lp) - (n.grid -2)^length(lp)

    crt.minimax.control <- do.call("crt.minimax.control", crt.minimax.control)
    # check if the length of x0 be equal to the length of lp and up!!
    #minimax.control$inner_maxeval <-  param_maxeval

    if (n.grid>0){
      crt.minimax.control$param_set <- make_grid(lp = lp, up = up, n.grid = n.grid)
      crt.minimax.control$inner_space <- "discrete"
    }else
      crt.minimax.control$inner_space <- "continuous"
    if (is.null(crtfunc))
      crt_type = "D" else
        crt_type = "user"
    if (!is.null(x))
      k <- length(x)/length(lx)


        out <- minimax_inner(formula = formula,
                         predvars = predvars, parvars = parvars, family = family,
                         lx = lx, ux = ux, lp = lp, up = up, iter = iter,
                         k = k,
                         fimfunc = fimfunc,
                         ICA.control = ICA.control,
                         sens.control = sens.control,
                         sens.minimax.control = sens.minimax.control,
                         crt.minimax.control = crt.minimax.control,
                         type = type,
                         initial = initial,
                         localdes = localdes,
                         npar = npar,
                         crt_type = crt_type,
                         multipars = list(),
                         plot_3d = plot_3d[1],
                         only_w_varlist = list(x = x),
                         user_crtfunc = crtfunc,
                         user_sensfunc = sensfunc)

        out$method = 'minimax' # 06202020@seongho
        if (!missing(formula)){
      out$call = formula # 06202020@seongho
    }else{
      out$call = NULL
    }

    dout = NULL
    fout = NULL
    fiter = length(out$evol)
    if(fiter>0){
      tout = c()
      for(i in 1:fiter){
        sout = out$evol[[i]]
        tout = rbind(tout,c(i,sout$x,sout$w,sout$min_cost,sout$mean_cost))
      }
      dout = as.data.frame(tout)
      #dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")

      if(length(sout$x)==length(sout$w)){
        dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx = c()
        for(i in 1:tlen){
          tdimx = c(tdimx,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(dout)[[2]] = c("iter",tdimx,paste("w",1:k,sep=""),"min_cost","mean_cost")
      }

      # extract sens outcomes
      sout = out$evol[[fiter]]
      tsens = capture.output(sout$sens)
      tpos.max = grep("Maximum",tsens)
      tpos.elb = grep("ELB",tsens)
      tpos.time = grep("Verification",tsens)
      tmax = NA
      telb = NA
      ttime = NA
      if(length(tpos.max)>0){
        tmax = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.max]),"is")[[1]][2])
      }
      if(length(tpos.elb)>0){
        telb = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.elb]),"is")[[1]][2])
      }
      if(length(tpos.time)>0){
        ttime = as.numeric(strsplit(gsub("seconds!","",gsub("\\s+","",tsens[tpos.time])),"required")[[1]][2])
      }
      t2out = c(fiter,sout$x,sout$w,sout$min_cost,sout$mean_cost,tmax,telb,ttime)
      fout = as.data.frame(t(t2out))
      #dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")

      if(length(sout$x)==length(sout$w)){
        dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx2 = c()
        for(i in 1:tlen){
          tdimx2 = c(tdimx2,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(fout)[[2]] = c("iter",tdimx2,paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }

    }

    out$out = dout
    #out$out2 = out$evol
    out$design = fout

    return(out)
}

######################################################################################################*
######################################################################################################*
#' @title Verifying Optimality of The Minimax and Standardized maximin D-optimal Designs
#'
#' @description
#'
#' It plots the sensitivity (derivative) function of the minimax or
#'  standardized maximin D-optimal criterion
#' at a given approximate (continuous) design and also
#'  calculates its efficiency lower bound (ELB) with respect
#' to the optimality criterion.
#' For an approximate (continuous) design, when the design space is one or two-dimensional,
#'  the user can visually verify the optimality of the design by observing the
#' sensitivity plot. Furthermore, the proximity of the design to the optimal design
#'  can be measured by the  ELB without knowing the latter.
#'  See, for more details, Masoudi et al. (2017).
#'
#' @inheritParams minimax
#' @param x Vector of the design (support) points. See 'Details' of \code{\link{sensminimax}} for models with more than one predictors.
#' @param w Vector of the corresponding design weights for \code{x}.
#' @param calculate_criterion Calculate the optimality criterion? See 'Details' of \code{\link{sensminimax}}.
#' @param plot_3d Which package should be used to plot the sensitivity (derivative) function for models with two predictors.
#'   Either \code{"rgl"} or \code{"lattice"} (default).
#' @param plot_sens Plot the sensitivity (derivative) function? Defaults to \code{TRUE}.
#' @param crt.minimax.control Control parameters to calculate the value of the  minimax or standardized maximin optimality criterion  over the  continuous parameter space.
#'   Only applicable when \code{calculate_criterion = TRUE}.
#'   For more details, see \code{\link{crt.minimax.control}}.
#' @param silent Do not print anything? Defaults to \code{FALSE}.
#' @param crtfunc (Optional) a function that specifies an arbitrary criterion. It must have especial arguments and output. See 'Details' of \code{\link{minimax}}.
#' @param sensfunc (Optional) a function that specifies the sensitivity function for \code{crtfunc}. See 'Details' of \code{\link{minimax}}.
#' @details
#' Let the unknown parameters belong to \eqn{\Theta}.
#' A design \eqn{\xi^*}{\xi*} is minimax D-optimal among all designs on \eqn{\chi} if and only if there exists a probability measure \eqn{\mu^*}{\mu*} on
#'    \deqn{A(\xi^*) = \left\{\nu \in \Theta \mid -log|M(\xi^*, \nu)| = \max_{\theta \in \Theta} -log|M(\xi^*, \theta)| \right\},}{
#'      A(\xi*) = {\nu belongs to \Theta where -log|M(\xi*, \nu) = maxima of function -log|M(\xi*, \theta)| with respect to \theta over \Theta} ,}
#'        such that the following inequality holds for all \eqn{\boldsymbol{x} \in \chi}{x belong to \chi}
#'         \deqn{c(\boldsymbol{x}, \mu^*, \xi^*) = \int_{A(\xi^*)} tr M^{-1}(\xi^*, \nu)I(\boldsymbol{x}, \nu)\mu^* d(\nu)-p \leq 0,}{
#'          c(x, \mu*, \xi*) = integration over A(\xi*) with integrand  tr M^-1(\xi*, \nu)I(x, \nu)\mu* d(\nu)-p <= 0,}
#'           with equality at all support points of \eqn{\xi^*}{\xi*}.
#'            Here, \eqn{p} is the number of model parameters. \eqn{c(\boldsymbol{x}, \mu^*, \xi^*)}{c(x, \mu*, \xi*)} is called \strong{sensitivity} or \strong{derivative} function.
#' The set \eqn{A(\xi^*)}{A(\xi*)} is sometimes called \bold{answering set} of
#'  \eqn{\xi^*}{\xi*} and the measure \eqn{\mu^*}{\mu*} is a sub-gradient of the
#'    non-differentiable criterion evaluated at \eqn{M(\xi^*,\nu)}{M(\xi*,\nu)}.\cr
#' For the standardized maximin D-optimal designs, the answering set \eqn{N(\xi^*)}{N(\xi*)} is
#'    \deqn{N(\xi^*) = \left\{\boldsymbol{\nu} \in \Theta \mid \mbox{eff}_D(\xi^*, \boldsymbol{\nu}) = \min_{\boldsymbol{\theta} \in \Theta} \mbox{eff}_D(\xi^*, \boldsymbol{\theta}) \right\}.
#'      }{N(\xi*) = \{\nu belongs to \Theta  where eff_D(\xi*, \nu) = minima of function eff_D(\xi*, \theta)  with respect to \theta over \Theta\},} where
#'      \eqn{\mbox{eff}_D(\xi, \boldsymbol{\theta}) =  (\frac{|M(\xi, \boldsymbol{\theta})|}{|M(\xi_{\boldsymbol{\theta}}, \boldsymbol{\theta})|})^\frac{1}{p}}{
#'      eff_D(\xi, \theta) =  (|M(\xi, \theta)|/|M(\xi_\theta, \theta)|)^(1/p)} and \eqn{\xi_\theta} is the locally D-optimal design with respect to \eqn{\theta}.
#'      See 'Details' of \code{\link{sens.minimax.control}} on how we find the answering set.
#'
#' The argument  \code{x} is the vector of design points.
#'  For design points with more than one dimension (the models with more than one predictors),
#'    it is a concatenation of the design points, but \strong{dimension-wise}.
#'    For example, let the model has three predictors   \eqn{(I, S, Z)}.
#'     Then,  a two-point optimal design has the following points:
#'    \eqn{\{\mbox{point1} = (I_1, S_1, Z_1), \mbox{point2} = (I_2, S_2, Z_2)\}}{{point1 = (I1, S1, Z1), point2 = (I2, S2, Z2)}}.
#'     Then, the argument \code{x} is equal to
#'     \code{x = c(I1, I2, S1, S2, Z1, Z2)}.
#'
#' ELB is a measure of  proximity of a design to the optimal design without knowing the latter.
#' Given a design, let \eqn{\epsilon} be the global maximum
#'  of the sensitivity (derivative) function with respect \eqn{x} where \eqn{x \in \chi}{x belong to \chi}.
#' ELB is given by \deqn{ELB = p/(p + \epsilon),}
#' where \eqn{p} is the number of model parameters. Obviously,
#' calculating ELB requires finding \eqn{\epsilon} and
#' another optimization problem to be solved.
#' The tuning parameters of this optimization can be regulated via the argument \code{\link{sens.minimax.control}}.
#' See, for more details, Masoudi et al. (2017).
#'
#'   The criterion value for the minimax D-optimal design is (global maximum over \eqn{\Theta})
#'  \deqn{\max_{\theta \in \Theta} -\log|M(\xi, \theta)|;}{max -log|M(\xi, \theta)|;}
#'  for the standardized maximin D-optimal design is (global minimum over \eqn{\Theta})
#'  \deqn{\inf_{\theta \in \Theta} \left[\left(\frac{|M(\xi, \theta)|}{|M(\xi_{\theta}, \theta)|}\right)^\frac{1}{p}\right].}{
#'   inf {|M(\xi, \theta)| / |M(\xi_\theta, \theta)|}^p.}
#'
#'  This function confirms the optimality assuming only a continuous parameter space \eqn{\Theta}.
#'
#' @return
#'  an object of class \code{sensminimax} that is a list with the following elements:
#'  \describe{
#'  \item{\code{type}}{Argument \code{type} that is required for print methods.}
#'  \item{\code{optima}}{A \code{matrix} that stores all the local optima over the parameter space.
#'   The cost  (criterion) values are stored in a column named \code{Criterion_Value}.
#'  The last column (\code{Answering_Set})
#'   shows if the optimum belongs to the answering set (1) or not (0). See 'Details' of \code{\link{sens.minimax.control}}.
#'    Only applicable for minimax or standardized maximin designs.}
#'  \item{\code{mu}}{Probability measure on the answering set.
#'   Corresponds to the rows of \code{optima} for which the associated row in column \code{Answering_Set} is equal to 1.
#'    Only applicable for minimax or standardized maximin designs.}
#'  \item{\code{max_deriv}}{Global maximum of the sensitivity (derivative) function (\eqn{\epsilon} in 'Details').}
#'  \item{\code{ELB}}{D-efficiency lower bound. Can not be larger than 1. If negative, see 'Note' in \code{\link{sensminimax}} or  \code{\link{sens.minimax.control}}.}
#'  \item{\code{merge_tol}}{Merging tolerance to create the answering set from the set of all local optima. See 'Details' in \code{\link{sens.minimax.control}}.
#'   Only applicable for minimax or standardized maximin designs.}
#'  \item{\code{crtval}}{Criterion value. Compare it with the column \code{Crtiterion_Value} in \code{optima} for minimax and standardized maximin designs.}
#'  \item{\code{time}}{Used CPU time (rough approximation).}
#'  }
#' @note
#' Theoretically, ELB can not be larger than 1. But if so, it may have one of the following reasons:
#' \itemize{
#' \item \code{max_deriv} is not a GLOBAL maximum.  Please increase  the value of the parameter \code{maxeval} in \code{\link{sens.minimax.control}} to find the global maximum.
#' \item The sensitivity function is shifted below the y-axis because
#' the number of model parameters has not been specified correctly (less value given).
#' Please specify the correct number of model parameters via argument \code{npar}.
#' }
#'  Please increase the value of the parameter
#'   \code{n_seg} in \code{\link{sens.minimax.control}}
#'    for  models with larger number of parameters or large parameter space to find the true
#'    answering set for minimax and standardized maximin designs. See \code{\link{sens.minimax.control}} for more details.
#' @references
#' Masoudi E, Holling H, Wong W.K. (2017). Application of Imperialist Competitive Algorithm to Find Minimax and Standardized Maximin Optimal Designs. Computational Statistics and Data Analysis, 113, 330-345. \cr
#' @example inst/examples/sensminimax_examples.R
#' @export
sensminimax <- function (formula, predvars, parvars,
                         family = gaussian(),
                         x, w,
                         lx, ux,
                         lp, up,
                         fimfunc = NULL,
                         standardized = FALSE,
                         localdes = NULL,
                         sens.control = list(),
                         sens.minimax.control = list(),
                         calculate_criterion = TRUE,
                         crt.minimax.control = list(),
                         plot_3d = c("lattice", "rgl"),
                         plot_sens = TRUE,
                         npar = length(lp),
                         silent = FALSE,
                         crtfunc = NULL,
                         sensfunc = NULL
){

  if (!is.logical(standardized))
    stop("'standardized' must be logical")
  if (standardized)
    type <- "standardized" else
      type <- "minimax"

    if(calculate_criterion){
      crt.minimax.control <- do.call("crt.minimax.control", crt.minimax.control)
      crt.minimax.control$inner_space <- "continuous"
    }
    if (is.null(crtfunc))
      crt_type = "D" else
        crt_type = "user"
      # check if the length of x0 be equal to the length of lp and up!!
      #minimax.control$inner_maxeval <-  param_maxeval

      # if (n.grid>0){
      #   crt.minimax.control$param_set <- make_grid(lp = lp, up = up, n.grid = n.grid)
      #   crt.minimax.control$inner_space <- "discrete"
      # }else


      out <- sensminimax_inner(formula = formula, predvars = predvars, parvars = parvars,
                               family = family,
                               x = x, w = w,
                               lx = lx, ux = ux,
                               lp = lp, up = up,
                               fimfunc = fimfunc,
                               sens.minimax.control =  sens.minimax.control,
                               sens.control = sens.control,
                               type = type,
                               localdes = localdes,
                               plot_3d = plot_3d[1],
                               plot_sens = plot_sens,
                               varlist = list(),
                               calledfrom = "sensfuncs",
                               npar = npar,
                               crt.minimax.control = crt.minimax.control,
                               calculate_criterion = calculate_criterion,
                               crt_type = crt_type,
                               multipars = list(),
                               silent = silent,
                               user_crtfunc = crtfunc,
                               user_sensfunc = sensfunc)
      out$method = "minimax" # 06222020@seongho

      return(out)
}
######################################################################################################*
######################################################################################################*
#' @title Locally D-Optimal Designs
#' @description
#'  Finds locally D-optimal designs for linear and nonlinear models.
#'  It should be used when a vector of initial estimates is available for the unknown model parameters.
#'  Locally optimal designs may not be efficient when the initial estimates are  far away from the true values of the parameters.
#' @inheritParams minimax
#' @param inipars A vector of initial estimates for the unknown parameters.
#' It must match \code{parvars} or the argument \code{param} of the function \code{fimfunc}, when provided.
#' @param npar Number of model parameters.  Used when \code{fimfunc} is given instead of \code{formula} to specify the number of model parameters.
#'   If not given, the sensitivity plot may be shifted below the y-axis.
#'   When \code{NULL}, it is set to \code{length(inipars)}.
#' @importFrom utils capture.output
#' @export
#' @seealso \code{\link{senslocally}}
#' @details
#'  Let \eqn{M(\xi, \theta_0)} be the Fisher information
#'   matrix (FIM) of a \eqn{k-}point design \eqn{\xi} and
#'    \eqn{\theta_0}  be the vector of the initial  estimates for the unknown parameters.
#'  A locally D-optimal design \eqn{\xi^*}{\xi*} minimizes over \eqn{\Xi}
#'   \deqn{-\log|M(\xi, \theta_0)|.}{-log|M(\xi, \theta_0)|.}
#'
#' One can adjust the tuning parameters in \code{\link{ICA.control}} to set a stopping rule
#' based on the general equivalence theorem. See "Examples" below.
#' @inherit minimax return
#'
#'
#' @references
#' Masoudi E, Holling H, Wong W.K. (2017). Application of Imperialist Competitive Algorithm to Find Minimax and Standardized Maximin Optimal Designs. Computational Statistics and Data Analysis, 113, 330-345. \cr
#' @example inst/examples/locally_examples.R
locally <- function(formula, predvars, parvars, family = gaussian(),
                    lx, ux,  iter, k,
                    inipars,
                    fimfunc = NULL,
                    ICA.control = list(),
                    sens.control = list(),
                    initial = NULL,
                    npar = length(inipars),
                    plot_3d = c("lattice", "rgl"),
                    x = NULL,
                    crtfunc = NULL,
                    sensfunc = NULL){


  if (!missing(formula)){
    if (length(inipars) != length(parvars))
      stop("lengtb of 'inipars' is not equal to the length of 'parvars'")
  }
  if (is.null(x))
    if (k < length(inipars))
      stop("\"k\" must be larger than the number of parameters to avoid singularity")
  if (!is.null(x))
    k <- length(x)/length(lx) # Bug!!! how you can understand the number of

  # if (!is.null(x)){
  #   #dim(x)[2] is the dimension of the predictors
  #   #dim(x)[1] is the number of the weights
  #
  #   ## lower bound and upper bound of the design space when only
  #   ## w is requested. Because lx and ux will be replcaed by 0 and 1,
  #   # when the x is given (w is only the objective variables)
  #   # only applied for equivalence theorem
  #   #lx_when_only_w <- rep(lx, length(x)/k)
  #   #ux_when_only_w <- rep(ux, length(x)/k)
  #   #lx_when_only_w <- lx
  #   #ux_when_only_w <- ux
  #   ## here lx and ux are not the lowerbound and upperbond of x, but w
  #   #lx <- rep(0, length(x)/k)
  #   #ux <- rep(1, length(x)/k)
  # }
  if (is.null(crtfunc))
    crt_type = "D" else
      crt_type = "user"


    #cat("#### BEFORE OUT ####\n")

    out <- minimax_inner(formula = formula,
                         predvars = predvars, parvars = parvars, family = family,
                         lx = lx, ux = ux, lp = inipars, up = inipars, iter = iter, k = k,
                         fimfunc = fimfunc,
                         ICA.control = ICA.control,
                         sens.control = sens.control,
                         crt.minimax.control = list(inner_space = "locally"),
                         type = "locally",
                         initial = initial,
                         localdes = NULL,
                         npar = npar,
                         robpars = list(),
                         crt_type = crt_type,
                         multipars = list(),
                         plot_3d = plot_3d[1],
                         only_w_varlist = list(x = x),
                         user_crtfunc = crtfunc,
                         user_sensfunc = sensfunc)

    out$method = 'locally' # 06202020@seongho
    if (!missing(formula)){
      out$call = formula # 06202020@seongho
    }else{
      out$call = NULL
    }

    #cat("#### AFTER OUT ####\n")

    dout = NULL
    fout = NULL
    fiter = length(out$evol)
    if(fiter>0){

      #cat("############-1-1-1-1-1-1- AT THE END OF OUT ##############\n")

      tout = c()
      for(i in 1:fiter){
        sout = out$evol[[i]]
        tout = rbind(tout,c(i,sout$x,sout$w,sout$min_cost,sout$mean_cost))
      }
      dout = as.data.frame(tout)
      #dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")

      #cat("############----------11111111111100000 AT THE END OF OUT ##############\n")


      if(length(sout$x)==length(sout$w)){
        dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx = c()
        for(i in 1:tlen){
          tdimx = c(tdimx,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(dout)[[2]] = c("iter",tdimx,paste("w",1:k,sep=""),"min_cost","mean_cost")
      }

      #cat("############----------11111111111122222222222200000 AT THE END OF OUT ##############\n")
      #cat("############ fiter = ",fiter," ############# -----\n")
      #print(out$evol[[fiter]])

      # extract sens outcomes
      sout = out$evol[[fiter]]
      tsens = capture.output(sout$sens)
      tpos.max = grep("Maximum",tsens)
      tpos.elb = grep("ELB",tsens)
      tpos.time = grep("Verification",tsens)
      tmax = NA
      telb = NA
      ttime = NA
      if(length(tpos.max)>0){
        tmax = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.max]),"is")[[1]][2])
      }
      if(length(tpos.elb)>0){
        telb = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.elb]),"is")[[1]][2])
      }
      if(length(tpos.time)>0){
        ttime = as.numeric(strsplit(gsub("seconds!","",gsub("\\s+","",tsens[tpos.time])),"required")[[1]][2])
      }
      t2out = c(fiter,sout$x,sout$w,sout$min_cost,sout$mean_cost,tmax,telb,ttime)
      fout = as.data.frame(t(t2out))
      #dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")

      #cat("############----------1111111111112222222222223333333333333300000 AT THE END OF OUT ##############\n")


      if(length(sout$x)==length(sout$w)){
        dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx2 = c()
        for(i in 1:tlen){
          tdimx2 = c(tdimx2,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(fout)[[2]] = c("iter",tdimx2,paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }

      #cat("############----------00000 AT THE END OF OUT ##############\n")

    }

    #cat("############00000 AT THE END OF OUT ##############\n")

    out$out = dout
    #out$out2 = out$evol
    out$design = fout

    #cat("############ AT THE END OF OUT ##############\n")

    return(out)
}

######################################################################################################*
######################################################################################################*
#' @title Verifying Optimality of The Locally D-optimal Designs
#' @description
#' It plots the sensitivity (derivative) function of the
#'  locally D-optimal criterion
#' at a given approximate (continuous) design and also
#'  calculates its efficiency lower bound (ELB) with respect
#' to the optimality criterion.
#' For an approximate (continuous) design, when the design space is one or two-dimensional,
#'  the user can visually verify the optimality of the design by observing the
#' sensitivity plot. Furthermore, the proximity of the design to the optimal design
#'  can be measured by the  ELB without knowing the latter.
#'  See, for more details, Masoudi et al. (2017).
#' @inheritParams sensminimax
#' @inheritParams locally
#' @param npar Number of model parameters.  Used when \code{fimfunc} is given instead of \code{formula} to specify the number of model parameters.
#'   If not given, the sensitivity plot may be shifted below the y-axis.
#'   When \code{NULL}, it is set to \code{length(inipars)}.
#' @example inst/examples/senslocally_examples.R
#' @inherit sensminimax return
#' @export
#' @details
#'
#' Let \eqn{\theta_0} denotes the vector of initial estimates for the unknown parameters.
#' A design \eqn{\xi^*}{\xi*} is locally D-optimal among all designs on \eqn{\chi} if and only if
#'  the following inequality holds for all \eqn{\boldsymbol{x} \in \chi}{x belong to \chi}
#'         \deqn{c(\boldsymbol{x}, \xi^*, \theta_0) =  tr M^{-1}(\xi^*, \theta_0)I(\boldsymbol{x}, \theta_0)-p \leq 0,}{
#'          c(x, \xi*, \theta_0) =  tr M^-1(\xi*, \theta0)I(x, \theta_0)-p <= 0,}
#'           with equality at all support points of \eqn{\xi^*}{\xi*}.
#'            Here, \eqn{p} is the number of model parameters.
#'             \eqn{c(\boldsymbol{x},\xi^*, \theta_0)}{c(x,\xi*, \theta_0)} is called \strong{sensitivity} or \strong{derivative} function.
#'
#' ELB is a measure of  proximity of a design to the optimal design without knowing the latter.
#' Given a design, let \eqn{\epsilon} be the global maximum
#'  of the sensitivity (derivative) function over \eqn{x \in \chi}{x belong to \chi}.
#' ELB is given by \deqn{ELB = p/(p + \epsilon),}
#' where \eqn{p} is the number of model parameters. Obviously,
#' calculating ELB requires finding \eqn{\epsilon} and
#' another optimization problem to be solved.
#' The tuning parameters of this optimization can be regulated via the argument  \code{\link{sens.minimax.control}}.
#' See, for more details, Masoudi et al. (2017).
#'
#' @note
#'
#' Theoretically, ELB can not be larger than 1. But if so, it may have one of the following reasons:
#' \itemize{
#' \item \code{max_deriv} is not a GLOBAL maximum.  Please increase  the value of the parameter \code{maxeval} in \code{\link{sens.minimax.control}} to find the global maximum.
#' \item The sensitivity function is shifted below the y-axis because
#' the number of model parameters has not been specified correctly (less value given).
#' Please specify the correct number of model parameters via the argument \code{npar}.
#' }
#'
#' @references
#' Masoudi E, Holling H, Wong W.K. (2017). Application of Imperialist Competitive Algorithm to Find Minimax and Standardized Maximin Optimal Designs. Computational Statistics and Data Analysis, 113, 330-345. \cr
senslocally <- function (formula, predvars, parvars,
                         family = gaussian(),
                         x, w,
                         lx, ux,
                         inipars,
                         fimfunc = NULL,
                         sens.control = list(),
                         calculate_criterion = TRUE,
                         plot_3d = c("lattice", "rgl"),
                         plot_sens = TRUE,
                         npar = length(inipars),
                         silent = FALSE,
                         crtfunc = NULL,
                         sensfunc = NULL){


  if (!missing(formula)){
    if (length(inipars) != length(parvars))
      stop("lengtb of 'inipars' is not equal to the length of 'parvars'")
  }
  if (is.null(npar))
    npar <- length(inipars)

  if (is.null(crtfunc))
    crt_type = "D" else
      crt_type = "user"


    out <- sensminimax_inner(formula = formula, predvars = predvars, parvars = parvars,
                             family = family,
                             x = x, w = w,
                             lx = lx, ux = ux,
                             lp = inipars, up = inipars,
                             fimfunc = fimfunc,
                             sens.control = sens.control,
                             type = "locally",
                             localdes = NULL,
                             plot_3d = plot_3d[1],
                             plot_sens = plot_sens,
                             varlist = list(),
                             calledfrom = "sensfuncs",
                             npar = npar,
                             crt.minimax.control = list(inner_space = "locally"),
                             calculate_criterion = calculate_criterion,
                             robpars = list(),
                             crt_type = crt_type,
                             multipars = list(),
                             silent = silent,
                             user_crtfunc = crtfunc,
                             user_sensfunc = sensfunc)
    out$method = "locally" # 06222020@seongho

    return(out)
}

######################################################################################################*
######################################################################################################*
#' @title Robust D-Optimal Designs
#'
#' @description
#' Finds Robust designs or optimal  in-average designs for linear and nonlinear models.
#'  It is useful when a set of different vectors of initial estimates
#'   along with a discrete probability measure
#'   are available for the unknown model parameters.
#'   It is a discrete version of \code{\link{bayes}}.
#' @inheritParams senslocally
#' @inheritParams locally
#' @param prob A vector of the probability measure \eqn{\pi} associated with each row of \code{parset}.
#' @param parset A matrix that provides the vector of initial estimates for the model parameters, i.e. support of \eqn{\pi}.
#'  Every row is one vector  (\code{nrow(parset) == length(prob)}). See 'Details'.
#' @param npar Number of model parameters.  Used when \code{fimfunc} is given instead of \code{formula} to specify the number of model parameters.
#'   If not given, the sensitivity plot may be shifted below the y-axis.
#'    When \code{NULL}, it is set to \code{dim(parset)[2]}.
#' @inherit locally return
#' @details
#' Let \eqn{\Theta} be a set of initial estimates for the unknown parameters.
#' A robust criterion is evaluated at the elements of \eqn{\Theta} weighted by a probability measure
#' \eqn{\pi} as follows:
#' \deqn{B(\xi, \pi) = \int_{\Theta}|M(\xi, \theta)|\pi(\theta) d\theta.}{
#' B(\xi, \Pi) = intergation over \Theta \Psi(\xi, \theta)\pi(\theta) d\theta.}
#' A robust design \eqn{\xi^*}{\xi*}   maximizes \eqn{B(\xi, \pi)} over the space of all designs.
#'
#'  When the model is given via \code{formula},
#'   columns of \code{parset} must match the parameters introduced
#'   in \code{parvars}.
#'   Otherwise, when the model is introduced via \code{fimfunc},
#'   columns of \code{parset} must match the argument \code{param} in \code{fimfunc}.
#'
#'  To verify the optimality of the output design by the general equivalence theorem,
#'  the user can either \code{plot} the results or set  \code{checkfreq} in \code{\link{ICA.control}}
#'  to \code{Inf}. In either way, the function \code{\link{sensrobust}} is called for verification.
#' One can also adjust the tuning parameters in \code{\link{ICA.control}} to set a stopping rule
#' based on the general equivalence theorem. See 'Examples' below.
#'
#' @importFrom utils capture.output
#' @export
#' @note
#' When a continuous prior distribution for the unknown model parameters is available,  use \code{\link{bayes}}.
#' When only one initial estimates of the unknown model parameters is available (\eqn{\Theta} has only one element),  use  \code{\link{locally}}.
#' @seealso \code{\link{bayes}} \code{\link{sensrobust}}
#' @example inst/examples/robust_examples.R
robust <- function(formula, predvars, parvars, family = gaussian(),
                   lx, ux,  iter, k,
                   prob,
                   parset,
                   fimfunc = NULL,
                   ICA.control = list(),
                   sens.control = list(),
                   initial = NULL,
                   npar = dim(parset)[2],
                   plot_3d = c("lattice", "rgl"),
                   x = NULL,
                   crtfunc = NULL,
                   sensfunc = NULL){


  if (length(prob) != dim(parset)[1])
    stop("length of \"prior\" is not equal to the number of rows of \"param\"")
  if (!missing(formula)){
    if (dim(parset)[2] != length(parvars))
      stop("number of columns of  'parset' is not equal to the length of 'parvars'")
  }
  if (k < dim(parset)[2])
    stop("\"k\" must be larger than the number of parameters to avoid singularity")
  if (is.null(crtfunc))
    crt_type = "D" else
      crt_type = "user"
    # if (is.null(npar))
    #   npar <- dim(parset)[2]
    ## you must provide npar
    if (!is.null(x))
      k <- length(x)/length(lx)


        out <- minimax_inner(formula = formula,
                         predvars = predvars, parvars = parvars,
                         family = family,
                         lx = lx, ux = ux, lp = NA, up = NA, iter = iter, k = k,
                         fimfunc = fimfunc,
                         ICA.control = ICA.control,
                         sens.control = sens.control,
                         crt.minimax.control = list(inner_space = "robust_set"),
                         type = "robust",
                         initial = initial,
                         localdes = NULL,
                         npar = npar,
                         robpars = list(prob = prob, parset = parset),
                         crt_type = crt_type,
                         multipars = list(),
                         plot_3d = plot_3d[1],
                         only_w_varlist = list(x = x),
                         user_crtfunc = crtfunc,
                         user_sensfunc = sensfunc)

        out$method = 'robust' # 06202020@seongho
        if (!missing(formula)){
      out$call = formula # 06202020@seongho
    }else{
      out$call = NULL
    }

    dout = NULL
    fout = NULL
    fiter = length(out$evol)
    if(fiter>0){
      tout = c()
      for(i in 1:fiter){
        sout = out$evol[[i]]
        tout = rbind(tout,c(i,sout$x,sout$w,sout$min_cost,sout$mean_cost))
      }
      dout = as.data.frame(tout)
      #dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")

      if(length(sout$x)==length(sout$w)){
        dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx = c()
        for(i in 1:tlen){
          tdimx = c(tdimx,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(dout)[[2]] = c("iter",tdimx,paste("w",1:k,sep=""),"min_cost","mean_cost")
      }

      # extract sens outcomes
      sout = out$evol[[fiter]]
      tsens = capture.output(sout$sens)
      tpos.max = grep("Maximum",tsens)
      tpos.elb = grep("ELB",tsens)
      tpos.time = grep("Verification",tsens)
      tmax = NA
      telb = NA
      ttime = NA
      if(length(tpos.max)>0){
        tmax = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.max]),"is")[[1]][2])
      }
      if(length(tpos.elb)>0){
        telb = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.elb]),"is")[[1]][2])
      }
      if(length(tpos.time)>0){
        ttime = as.numeric(strsplit(gsub("seconds!","",gsub("\\s+","",tsens[tpos.time])),"required")[[1]][2])
      }
      t2out = c(fiter,sout$x,sout$w,sout$min_cost,sout$mean_cost,tmax,telb,ttime)
      fout = as.data.frame(t(t2out))
      #dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")

      if(length(sout$x)==length(sout$w)){
        dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx2 = c()
        for(i in 1:tlen){
          tdimx2 = c(tdimx2,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(fout)[[2]] = c("iter",tdimx2,paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }

    }

    out$out = dout
    #out$out2 = out$evol
    out$design = fout

    return(out)
}
######################################################################################################*
######################################################################################################*
#' @title Verifying Optimality of The Robust Designs
#'
#' @description
#' It plots the sensitivity (derivative) function of the
#'  robust criterion
#' at a given approximate (continuous) design and also
#'  calculates its efficiency lower bound (ELB) with respect
#' to the optimality criterion.
#' For an approximate (continuous) design, when the design space is one or two-dimensional,
#'  the user can visually verify the optimality of the design by observing the
#' sensitivity plot. Furthermore, the proximity of the design to the optimal design
#'  can be measured by the  ELB without knowing the latter.
#'  See, for more details, Masoudi et al. (2017).
#' @inheritParams robust
#' @inheritParams senslocally
#' @inherit senslocally return
#' @details
#' Let \eqn{\Theta}  be the set initial estimates for the model parameters and \eqn{\pi} be a probability measure having support in  \eqn{\Theta}.
#' A design \eqn{\xi^*}{\xi*} is robust with respect to  \eqn{\pi}
#' if the following inequality holds for all \eqn{\boldsymbol{x} \in \chi}{x belong to \chi}:
#'  \deqn{c(\boldsymbol{x}, \pi, \xi^*) = \int_{\pi} tr M^{-1}(\xi^*, \theta)I(\boldsymbol{x}, \theta)\pi(\theta) d(\theta)-p \leq 0,}{
#'          c(x, \pi, \xi*)  = integration over \pi with integrand tr M^-1(\xi*, \theta)I(x, \theta)\pi(\theta) d(\theta)-p <= 0}
#'           with equality at all support points of \eqn{\xi^*}{\xi*}.
#'            Here, \eqn{p} is the number of model parameters.
#'
#'  ELB is a measure of  proximity of a design to the optimal design without knowing the latter.
#' Given a design, let \eqn{\epsilon} be the global maximum
#'  of the sensitivity (derivative) function over \eqn{x \in \chi}{x belong to \chi}.
#' ELB is given by \deqn{ELB = p/(p + \epsilon),}
#' where \eqn{p} is the number of model parameters. Obviously,
#' calculating ELB requires finding \eqn{\epsilon} and
#' another optimization problem to be solved.
#' The tuning parameters of this optimization can be regulated via the argument  \code{\link{sens.minimax.control}}.
#'
#' @note
#' Theoretically, ELB can not be larger than 1. But if so, it may have one of the following reasons:
#' \itemize{
#' \item \code{max_deriv} is not a GLOBAL maximum.  Please increase  the value of the parameter \code{maxeval} in \code{\link{sens.minimax.control}} to find the global maximum.
#' \item The sensitivity function is shifted below the y-axis because
#' the number of model parameters has not been specified correctly (less value given).
#' Please specify the correct number of model parameters via the argument \code{npar}.
#' }
#'
#'
#' @seealso \code{\link{bayes}} \code{\link{sensbayes}} \code{\link{robust}}
#' @export
#' @example inst/examples/sensrobust_examples.R
sensrobust <- function (formula, predvars, parvars, family = gaussian(),
                        x, w,
                        lx, ux,
                        prob,
                        parset,
                        fimfunc = NULL,
                        sens.control = list(),
                        calculate_criterion = TRUE,
                        plot_3d = c("lattice", "rgl"),
                        plot_sens = TRUE,
                        npar = dim(parset)[2],
                        silent = FALSE,
                        crtfunc = NULL,
                        sensfunc = NULL){


  if (length(prob) != dim(parset)[1])
    stop("length of \"prior\" is not equal to the number of rows of \"param\"")
  if (!missing(formula)){
    if (dim(parset)[2] != length(parvars))
      stop("number of columns of  'parset' is not equal to the length of 'parvars'")
  }
  if (is.null(crtfunc))
    crt_type = "D" else
      crt_type = "user"
    # if (is.null(npar))
    #   npar <- dim(parset)[2]
    ## you must provide npar


    out <- sensminimax_inner(formula = formula, predvars = predvars, parvars = parvars,
                             family = family,
                             x = x, w = w,
                             lx = lx, ux = ux,
                             lp = NA, up = NA,
                             fimfunc = fimfunc,
                             sens.control = sens.control,
                             type = "robust",
                             localdes = NULL,
                             plot_3d = plot_3d[1],
                             plot_sens = plot_sens,
                             varlist = list(),
                             calledfrom = "sensfuncs",
                             npar = npar,
                             crt.minimax.control = list(inner_space = "robust_set"),
                             calculate_criterion = calculate_criterion,
                             robpars = list(prob = prob, parset = parset),
                             crt_type = crt_type,
                             multipars = list(),
                             silent = silent,
                             user_crtfunc = crtfunc,
                             user_sensfunc = sensfunc)
    out$method = "robust" # 06222020@seongho

    return(out)
}
######################################################################################################*
######################################################################################################*
#' @title
#' Locally Multiple Objective Optimal Designs for the 4-Parameter Hill Model
#'
#' @description
#'  The 4-parameter Hill model is of the form
#'  \deqn{f(D) = c + \frac{(d-c)(\frac{D}{a})^b}{1+(\frac{D}{a})^b} + \epsilon,}{
#'  f(D) = c + (d-c)(D/a)^b/(1 + (D/a)^b) + \epsilon,}
#' where \eqn{\epsilon \sim N(0, \sigma^2)}{\epsilon ~ N(0, \sigma^2)},
#'  \eqn{D} is the dose level and the predictor,
#' \eqn{a} is the ED50,
#'  \eqn{d} is the upper limit of response,
#'   \eqn{c} is the lower limit of response and
#'    \eqn{b} denotes the Hill constant that
#'  control the flexibility in the slope of the response curve.\cr
#'  Sometimes, the Hill model is re-parameterized and written as
#'  \deqn{f(x) = \frac{\theta_1}{1 + exp(\theta_2 x + \theta_3)} + \theta_4,}{
#'  f(x)= \theta_1/(1 + exp(\theta_2*x + \theta_3)) + \theta_4,}
#'   where \eqn{\theta_1 = d - c}, \eqn{\theta_2 = - b},
#'   \eqn{\theta_3 = b\log(a)}{\theta_3 = b*log(a)}, \eqn{\theta_4 = c}, \eqn{\theta_1 > 0},
#'   \eqn{\theta_2 \neq 0}{\theta_2 not equal to 0}, and \eqn{-\infty < ED50 < \infty},
#'   where \eqn{x = log(D) \in [-M, M]}{x = log(D) belongs to [-M, M]}
#'   for some sufficiently large value of \eqn{M}.
#'   The new form is sometimes called  4-parameter logistic model.\cr
#'  The function \code{multiple} finds locally multiple-objective optimal designs for estimating the model parameters, the ED50, and the MED, simultaneously.
#'    For more details, see Hyun and  Wong (2015).
#'
#' @param minDose Minimum dose \eqn{D}. For the 4-parameter logistic model, i.e. when \code{Hill_par = FALSE}, it is the minimum of \eqn{log(D)}.
#' @param maxDose  Maximum dose \eqn{D}. For the 4-parameter logistic model, i.e. when \code{Hill_par = FALSE}, it is the maximum of \eqn{log(D)}.
#' @inheritParams minimax
#' @param lambda A vector of relative importance of each of the three criteria,
#'  i.e. \eqn{\lambda = (\lambda_1, \lambda_2, \lambda_3)}.
#'   Here \eqn{0 < \lambda_i < 1} and  s \eqn{\sum \lambda_i = 1}.
# user select weights, where \eqn{\lambda_1}{\lambda1} is the weight for estimating parameters,
# \eqn{\lambda_2}{\lambda2} is the weight for estimating median effective dose level (ED50), and \eqn{\lambda_3}{\lambda3} is the weight for estimating minimum effective dose level (MED).
#' @param delta   Predetermined meaningful value of the minimum effective dose MED.
#' When \eqn{\delta < 0 }, then \eqn{\theta_2 > 0} or when \eqn{\delta > 0}, then \eqn{\theta_2 < 0}.
#' @param inipars A vector of initial estimates for the vector of parameters  \eqn{(a, b, c, d)}.
#'  For the 4-parameter logistic model, i.e. when \code{Hill_par = FALSE},
#'  it is  a vector of initial estimates for \eqn{(\theta_1, \theta_2,\theta_3, \theta_4)}.
#' @param Hill_par Hill model parameterization? Defaults to \code{TRUE}.
#' @param tol Tolerance for finding the general inverse of the Fisher information matrix. Defaults to \code{.Machine$double.xmin}.
#' @references
#' Hyun, S. W., and Wong, W. K. (2015). Multiple-Objective Optimal Designs for Studying the Dose Response Function and Interesting Dose Levels. The international journal of biostatistics, 11(2), 253-271.
#' @details
#'  When \eqn{\lambda_1 > 0}, then the number of support points \code{k}
#'   must at least be four to avoid singularity of the Fisher information matrix.
#'
#' One can adjust the tuning parameters in \code{\link{ICA.control}} to set a stopping rule
#' based on the general equivalence theorem. See 'Examples' below.
#' @note
#' This function is NOT appropriate for  finding  c-optimal designs for estimating 'MED' or 'ED50' (single objective optimal designs)
#'  and  the results may not be stable.
#'  The reason is that for the c-optimal criterion
#'  the generalized inverse of the Fisher information matrix
#'   is not stable and depends
#'  on the tolerance value (\code{tol}).
#' @importFrom utils capture.output
#' @export
#' @inherit locally return
#' @seealso \code{\link{sensmultiple}}
#' @example inst/examples/multiple_examples.R
multiple <- function(minDose, maxDose,
                     iter, k,
                     inipars,
                     Hill_par = TRUE,
                     delta,
                     lambda,
                     fimfunc = NULL,
                     ICA.control = list(),
                     sens.control = list(),
                     initial = NULL,
                     tol = sqrt(.Machine$double.xmin),
                     x = NULL){

  lx <- minDose
  ux <- maxDose
  if (length(lambda) != 3)
    stop("length of 'lambda' must be 3")
  if (sum(lambda) != 1)
    stop("sum of 'lambda' must be 1")
  if(any(lambda >1) || any(lambda < 0))
    stop("each element of 'lambda' must be between 0 an 1")
  if (!is.numeric(delta))
    stop("'delta' must be numeric")
  if (!is.logical(Hill_par))
    stop("'Hill_param' must be logical")
  if (any(lx > ux))
    stop("'ux' must be greater than lx")
  if (length(inipars) != 4)
    stop("length of 'inipars' must be 4")
  if (k < length(inipars))
    stop("\"k\" must be larger than the number of parameters to avoid singularity")

  if (!Hill_par){
    names(inipars) <- paste("theta", 1:4, sep = "")
    if (inipars["theta2"] < 0)
      if (!delta>0)
        stop("'delta > 0' when theta2 < 0'")
    if (inipars["theta2"] > 0)
      if (!delta<0)
        stop("'delta < 0' when theta2 > 0'")
    if (round(inipars["theta2"], 5) == 0)
      stop("'theta2 can not be zero")
    if (inipars["theta1"]<= 0)
      stop("theta1 must be positive")
  }else{
    names(inipars) <- letters[1:4]
    if (inipars["a"] <= 0 || inipars["d"] <= 0 || inipars["c"] <= 0)
      stop("a, c, and d must be positive")
    if (inipars["c"] > inipars["d"])
      if (lx <= 0)
        stop("'lx' must be positive")
    lx <- log(lx)
    ux <- log(ux)
    if (any(is.nan(c(lx, ux))))
      stop("'NaN produced for 'lx' or 'ux' when taking logarithm. Provide 'lx' and 'ux' accroding to the Hill model parameterization")
    inipars <- c(theta1 = inipars["d"]-inipars["c"], theta2 = -inipars["b"], theta3 = inipars["b"] * log(inipars["a"]), theta4 = inipars["c"])
    if (!is.null(x)) # we should convert the x to the scale of the 4PL model
      x <- log(x)
  }

  ## you must provide npar
  out <- minimax_inner(lx = lx, ux = ux, lp = inipars, up = inipars,
                       iter = iter, k = k,
                       fimfunc = FIM_logistic_4par,
                       ICA.control = ICA.control,
                       sens.control = sens.control,
                       crt.minimax.control = list(inner_space = "locally"),
                       type = "locally",
                       initial = initial,
                       localdes = NULL,
                       npar = 4,
                       robpars = list(),
                       crt_type = "multiple",
                       multipars = list(delta = delta, lambda = lambda, tol = tol),
                       plot_3d = "lattice",
                       only_w_varlist = list(x = x))
  #if (Hill_par)
  #  for (j in 1:length(out$evol))
  #    out$evol[[j]]$x <- exp(out$evol[[j]]$x)
  out$method = 'locally' # 06202020@seongho
  #if (!missing(formula)){
  #  out$call = formula # 06202020@seongho
  #}else{
    out$call = NULL
  #}

  dout = NULL
  fout = NULL
  fiter = length(out$evol)
  if(fiter>0){
    tout = c()
    for(i in 1:fiter){
      sout = out$evol[[i]]
      tout = rbind(tout,c(i,sout$x,sout$w,sout$min_cost,sout$mean_cost))
    }
    dout = as.data.frame(tout)
    #dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")

    if(length(sout$x)==length(sout$w)){
      dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")
    }else{
      tlen = length(sout$x)/length(sout$w)
      tdimx = c()
      for(i in 1:tlen){
        tdimx = c(tdimx,paste(paste("x",i,sep=""),1:k,sep=""))
      }
      dimnames(dout)[[2]] = c("iter",tdimx,paste("w",1:k,sep=""),"min_cost","mean_cost")
    }

    # extract sens outcomes
    sout = out$evol[[fiter]]
    tsens = capture.output(sout$sens)
    tpos.max = grep("Maximum",tsens)
    tpos.elb = grep("ELB",tsens)
    tpos.time = grep("Verification",tsens)
    tmax = NA
    telb = NA
    ttime = NA
    if(length(tpos.max)>0){
      tmax = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.max]),"is")[[1]][2])
    }
    if(length(tpos.elb)>0){
      telb = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.elb]),"is")[[1]][2])
    }
    if(length(tpos.time)>0){
      ttime = as.numeric(strsplit(gsub("seconds!","",gsub("\\s+","",tsens[tpos.time])),"required")[[1]][2])
    }
    t2out = c(fiter,sout$x,sout$w,sout$min_cost,sout$mean_cost,tmax,telb,ttime)
    fout = as.data.frame(t(t2out))
    #dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")

    if(length(sout$x)==length(sout$w)){
      dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
    }else{
      tlen = length(sout$x)/length(sout$w)
      tdimx2 = c()
      for(i in 1:tlen){
        tdimx2 = c(tdimx2,paste(paste("x",i,sep=""),1:k,sep=""))
      }
      dimnames(fout)[[2]] = c("iter",tdimx2,paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
    }

  }

  out$out = dout
  #out$out2 = out$evol
  out$design = fout

  return(out)
}

######################################################################################################*
######################################################################################################*
#' @title Verifying Optimality of The Multiple Objective Designs for The 4-Parameter Hill Model
#'
#' @description
#' This function uses general equivalence theorem to verify
#' the optimality of a multiple objective optimal design found for
#'  the 4-Parameter Hill model and  the 4-parameter logistic model.
#' For more details, See Hyun and Wong (2015).
#' @inheritParams multiple
#' @param dose A vector of design points. It is  either dose values or logarithm of dose values when \code{Hill_par = TRUE}.
#' @param w A vector of design weights.
#' @param silent Do not print anything? Defaults to \code{FALSE}.
#' @param calculate_criterion Calculate the criterion? Defaults to \code{TRUE}.
#' @param plot_sens Plot the sensitivity (derivative) function? Defaults to \code{TRUE}.
#' @export
#' @inherit senslocally return
#' @inherit multiple details
#' @details
#' ELB is a measure of  proximity of a design to the optimal design without knowing the latter.
#' Given a design, let \eqn{\epsilon} be the global maximum
#'  of the sensitivity (derivative) function over \eqn{x \in \chi}{x belong to \chi}.
#' ELB is given by \deqn{ELB = p/(p + \epsilon),}
#' where \eqn{p} is the number of model parameters. Obviously,
#' calculating ELB requires finding \eqn{\epsilon} and
#' another optimization problem to be solved.
#' The tuning parameters of this optimization can be regulated via the argument  \code{\link{sens.minimax.control}}.
#' See, for more details, Masoudi et al. (2017).
#'
#' @note
#' DO NOT use this function to verify  c-optimal designs for estimating 'MED' or 'ED50' (verifying single objective optimal designs) because the results may be unstable.
#'  The reason is that for the c-optimal criterion the generalized inverse of the Fisher information matrix is not stable and depends
#'  on the tolerance value (\code{tol}).
#'
#'  Theoretically, ELB can not be larger than 1. But if so, it may have one of the following reasons:
#' \itemize{
#' \item \code{max_deriv} is not a GLOBAL maximum.  Please increase  the value of the parameter \code{maxeval} in \code{\link{sens.minimax.control}} to find the global maximum.
#' \item The sensitivity function is shifted below the y-axis because
#' the number of model parameters has not been specified correctly (less value given).
#' Please specify the correct number of model parameters via argument \code{npar}.
#' }
#' @references
#' Hyun, S. W., and Wong, W. K. (2015). Multiple-Objective Optimal Designs for Studying the Dose Response Function and Interesting Dose Levels. The international journal of biostatistics, 11(2), 253-271.
#' @seealso \code{\link{multiple}}
#' @example inst/examples/sensmultiple_examples.R
sensmultiple <- function (dose, w,
                          minDose, maxDose,
                          inipars,
                          lambda,
                          delta,
                          Hill_par = TRUE,
                          sens.control = list(),
                          calculate_criterion = TRUE,
                          plot_sens = TRUE,
                          tol = sqrt(.Machine$double.xmin),
                          silent = FALSE){
  x <- dose
  lx <- minDose
  ux <- maxDose
  if (length(x) != length(w))
    stop("length of 'x' and 'w' is not equal")
  if (length(lambda) != 3)
    stop("length of 'lambda' must be 3")
  if (sum(lambda) != 1)
    stop("sum of 'lambda' must be 1")
  if(any(lambda >1) || any(lambda < 0))
    stop("each element of 'lambda' must be between 0 an 1")
  if (!is.numeric(delta))
    stop("'delta' must be numeric")
  if (!is.logical(Hill_par))
    stop("'Hill_param' must be logical")
  if (any(lx > ux))
    stop("'ux' must be greater than lx")
  if (length(inipars) != 4)
    stop("length of 'inipars' must be 4")
  if (!Hill_par){
    names(inipars) <- paste("theta", 1:4, sep = "")
    if (inipars["theta2"] < 0)
      if (!delta>0)
        stop("'delta > 0' when theta2 < 0'")
    if (inipars["theta2"] > 0)
      if (!delta<0)
        stop("'delta < 0' when theta2 > 0'")
    if (round(inipars["theta2"], 5) == 0)
      stop("'theta2 can not be zero")
    if (inipars["theta1"]<= 0)
      stop("theta1 must be positive")
  }else{
    names(inipars) <- letters[1:4]
    if (inipars["a"] <= 0 || inipars["d"] <= 0 || inipars["c"] <= 0)
      stop("a, c, and d must be positive")
    if (inipars["c"] > inipars["d"])
      if (lx <= 0)
        stop("'lx' must be positive")
    lx <- log(lx)
    ux <- log(ux)
    x <- log(x)
    if (any(is.nan(c(lx, ux))))
      stop("'NaN produced for 'lx' or 'ux' when taking logarithm. Provide 'lx' and 'ux' accroding to the Hill model parameterization")
    inipars <- c(theta1 = inipars["d"]-inipars["c"], theta2 = -inipars["b"], theta3 = inipars["b"] * log(inipars["a"]), theta4 = inipars["c"])
  }

  out <- sensminimax_inner(x = x, w = w,
                           lx = lx, ux = ux,
                           lp = inipars, up = inipars,
                           fimfunc = FIM_logistic_4par,
                           sens.control = sens.control,
                           type = "locally",
                           localdes = NULL,
                           plot_3d = "lattice", # not used
                           plot_sens = plot_sens,
                           varlist = list(),
                           calledfrom = "sensfuncs",
                           npar = 4,
                           crt.minimax.control = list(inner_space = "locally"),
                           calculate_criterion = calculate_criterion,
                           robpars = list(),
                           crt_type = "multiple",
                           multipars = list(delta = delta, lambda = lambda, tol = tol),
                           silent = silent)
  out$method = "locally" # 06222020@seongho

  return(out)
}

######################################################################################################*
######################################################################################################*
#' @title Locally DP-Optimal Designs
#' @inheritParams minimax
#' @inheritParams bayescomp
#' @param inipars Vector. Initial values for the unknown parameters. It will be passed to the information matrix and also probability function.
#' @param k Number of design points. When \code{alpha = 0}, then \code{k} can be less than the number of parameters.
#' @param npar Number of model parameters.  Used when \code{fimfunc} is given instead of \code{formula} to specify the number of model parameters.
#'   If not given, the sensitivity plot may be shifted below the y-axis. When \code{NULL}, it will be set here to \code{length(inipars)}.
#' @importFrom utils capture.output
#' @export
#' @inherit locally return
#' @description
#'  Finds compound locally DP-optimal designs that meet the dual goal of parameter estimation and
#'   increasing the probability of a particular outcome in a binary response model.
#'A compound locally DP-optimal design maximizes  the product of the efficiencies of a design \eqn{\xi} with respect to D- and average P-optimality, weighted by a pre-defined mixing constant
#' \eqn{0 \leq \alpha \leq 1}{0 <= \alpha <= 1}.
#' @details
#' Let \eqn{\Xi} be the space of all  approximate designs with
#'  \eqn{k} design points (support points) at \eqn{x_1, x_2, ...,  x_k}
#'   from  design space \eqn{\chi} with
#'  corresponding weights  \eqn{w_1,... ,w_k}.
#'  Let \eqn{M(\xi, \theta)} be the Fisher information
#'   matrix (FIM) of a \eqn{k-}point design \eqn{\xi},
#'    \eqn{\theta_0} is a user-given vector of initial estimates for the  unknown parameters \eqn{\theta} and
#'    \eqn{p(x_i, \theta)} is the ith probability of success
#' given by \eqn{x_i} in a binary response model.
#'   A compound locally DP-optimal design   maximizes over \eqn{\Xi}
#' \deqn{ \frac{\alpha}{q}\log|M(\xi, \theta_0)| + (1- \alpha)
#'\log \left( \sum_{i=1}^k w_ip(x_i, \theta_0) \right).}{
#'  \alpha/q log|M(\xi, \theta_0)| + (1- \alpha)
#'log ( \sum w_i p(x_i, \theta_0)).
#'}
#'
#' Use \code{\link{plot}} function to verify the general equivalence theorem for the output design or change \code{checkfreq} in \code{\link{ICA.control}}.
#'
#' One can adjust the tuning parameters in \code{\link{ICA.control}} to set a stopping rule
#' based on the general equivalence theorem. See "Examples" in \code{\link{locally}}.
#' @example inst/examples/locallycomp_examples.R
#' @references  McGree, J. M., Eccleston, J. A., and Duffull, S. B. (2008). Compound optimal design criteria for nonlinear models. Journal of Biopharmaceutical Statistics, 18(4), 646-661.
locallycomp <- function(formula, predvars, parvars, family = gaussian(),
                        lx, ux,
                        alpha,
                        prob,
                        iter, k,
                        inipars,
                        fimfunc = NULL,
                        ICA.control = list(),
                        sens.control = list(),
                        initial = NULL,
                        npar = length(inipars),
                        plot_3d = c("lattice", "rgl")){


  if (!missing(formula)){
    if (length(inipars) != length(parvars))
      stop("lengtb of 'inipars' is not equal to the length of 'parvars'")
  }
  if (alpha !=0)
    if (k < length(inipars))
      stop("\"k\" must be larger than the number of parameters to avoid singularity")

  if (is.formula(prob)){
    prob <- create_prob(prob = prob, predvars = predvars, parvars = parvars)
  }else{
    if (!is.function(prob))
      stop("'prob' must be either a function or a formula")
    if (!formalArgs(prob) %in% c("x", "param"))
      stop("arguments of 'prob' must be 'x' and 'param'")
  }

    out <- minimax_inner(formula = formula,
                       predvars = predvars, parvars = parvars, family = family,
                       lx = lx, ux = ux, lp = inipars, up = inipars, iter = iter, k = k,
                       fimfunc = fimfunc,
                       ICA.control = ICA.control,
                       sens.control = sens.control,
                       crt.minimax.control = list(inner_space = "locally"),
                       type = "locally",
                       initial = initial,
                       localdes = NULL,
                       npar = npar,
                       robpars = list(),
                       crt_type = "DPA",
                       multipars = list(),
                       plot_3d = plot_3d[1],
                       compound = list(prob = prob, alpha = alpha, npar = npar))


    out$method = 'locally' # 06202020@seongho

    if (!missing(formula)){
    out$call = formula # 06202020@seongho
  }else{
    out$call = NULL
  }

  plen = length(predvars)

  dout = NULL
  fout = NULL
  if(!is.null(out$evol)){
  #if(F){
    fiter = length(out$evol)
    if(fiter>0){
      tout = c()
      for(i in 1:fiter){
        sout = out$evol[[i]]
        tout = rbind(tout,c(i,sout$x,sout$w,sout$min_cost,sout$mean_cost))
      }
      dout = as.data.frame(tout)
      if(plen==1){
        dimnames(dout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost")
      }else{
        tdimx = c()
        for(i in 1:plen){
          tdimx = c(tdimx,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(dout)[[2]] = c("iter",tdimx,paste("w",1:k,sep=""),"min_cost","mean_cost")
      }
      # extract sens outcomes
      sout = out$evol[[fiter]]
      tsens = capture.output(sout$sens)
      tpos.max = grep("Maximum",tsens)
      tpos.elb = grep("ELB",tsens)
      tpos.time = grep("Verification",tsens)
      tmax = NA
      telb = NA
      ttime = NA
      if(length(tpos.max)>0){
        tmax = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.max]),"is")[[1]][2])
      }
      if(length(tpos.elb)>0){
        telb = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.elb]),"is")[[1]][2])
      }
      if(length(tpos.time)>0){
        ttime = as.numeric(strsplit(gsub("seconds!","",gsub("\\s+","",tsens[tpos.time])),"required")[[1]][2])
      }
      t2out = c(fiter,sout$x,sout$w,sout$min_cost,sout$mean_cost,tmax,telb,ttime)
      fout = as.data.frame(t(t2out))
      if(plen==1){
        dimnames(fout)[[2]] = c("iter",paste("x",1:k,sep=""),paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }else{
        tdimx = c()
        for(i in 1:plen){
          tdimx = c(tdimx,paste(paste("x",i,sep=""),1:k,sep=""))
        }
        dimnames(fout)[[2]] = c("iter",tdimx,paste("w",1:k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }
    }
  }
  out$out = dout
  #out$out2 = out$evol
  out$design = fout

  return(out)
}
######################################################################################################*
######################################################################################################*
#' @title Verifying Optimality of The Locally DP-optimal Designs
#' @inheritParams sensminimax
#' @inheritParams sensbayescomp
#' @param inipars Vector of initial estimates for the unknown parameters.
#' It must match \code{parvars} or argument \code{param} of the function provided in \code{fimfunc}.
#' @param npar Number of model parameters.  Used when \code{fimfunc} is given instead of \code{formula} to specify the number of model parameters.
#'   If not given, the sensitivity plot may be shifted below the y-axis.
#'   When \code{NULL}, it is set  to \code{length(inipars)}.
#'@description
#'  This function plot the sensitivity (derivative) function given an approximate (continuous) design and calculate the efficiency lower bound (ELB) for locally DP-optimal designs.
#' Let \eqn{\boldsymbol{x}}{x} belongs to \eqn{\chi} that denotes the design space.
#' Based on the general equivalence theorem, generally, a design \eqn{\xi^*}{\xi*} is optimal if and only if the value of its sensitivity (derivative) function
#' be non-positive for all \eqn{\boldsymbol{x}}{x} in \eqn{\chi} and it only reaches zero
#' when \eqn{\boldsymbol{x}}{x} belong to the support of \eqn{\xi^*}{\xi*} (be equal to one of the design point).
#' Therefore, the user can look at the sensitivity plot and the ELB to decide whether the
#' design is optimal or close enough to the true optimal design.
#'
#' @export
#' @inherit senslocally return
#' @example inst/examples/senslocallycomp_examples.R
#' @references  McGree, J. M., Eccleston, J. A., and Duffull, S. B. (2008). Compound optimal design criteria for nonlinear models. Journal of Biopharmaceutical Statistics, 18(4), 646-661.
senslocallycomp <- function (formula, predvars, parvars,
                             alpha,
                             prob,
                             family = gaussian(),
                             x, w,
                             lx, ux,
                             inipars,
                             fimfunc = NULL,
                             sens.control = list(),
                             calculate_criterion = TRUE,
                             plot_3d = c("lattice", "rgl"),
                             plot_sens = TRUE,
                             npar = length(inipars),
                             silent = FALSE){


  if (!missing(formula)){
    if (length(inipars) != length(parvars))
      stop("lengtb of 'inipars' is not equal to the length of 'parvars'")
  }

  if (is.formula(prob)){
    prob <- create_prob(prob = prob, predvars = predvars, parvars = parvars)
  }else{
    if (!is.function(prob))
      stop("'prob' must be either a function or a formula")
    if (!formalArgs(prob) %in% c("x", "param"))
      stop("arguments of 'prob' must be 'x' and 'param'")
  }


  out <- sensminimax_inner(formula = formula, predvars = predvars, parvars = parvars,
                           family = family,
                           x = x, w = w,
                           lx = lx, ux = ux,
                           lp = inipars, up = inipars,
                           fimfunc = fimfunc,
                           sens.control =  sens.control,
                           type = "locally",
                           localdes = NULL,
                           plot_3d = plot_3d[1],
                           plot_sens = plot_sens,
                           varlist = list(),
                           calledfrom = "sensfuncs",
                           npar = npar,
                           crt.minimax.control = list(inner_space = "locally"),
                           calculate_criterion = calculate_criterion,
                           robpars = list(),
                           crt_type = "DPA",
                           multipars = list(),
                           silent = silent,
                           compound = list(prob = prob, alpha = alpha, npar = npar))

  out$method = "locally" # 06222020@seongho

  return(out)
}

######################################################################################################*
######################################################################################################*
#  roxygen
#' Plotting \code{minimax} Objects
#' @description
#'  This function plots the evolution of the ICA algorithm (iteration vs the best (minimum) criterion value at each iteration) and also verifies the optimality of the last obtained design
#'  using  the general equivalence theorem. It plots the sensitivity function and calculates the ELB for the  best design generated at iteration number  \code{iter}.
#' @param x An object of class \code{minimax}.
#' @param iter Iteration number. if \code{NULL} (default), it will be set to the last iteration.
#' @param sensitivity Logical. If \code{TRUE} (default), the general equivalence theorem is used to check the optimality if the best design in iteration number \code{iter} and the sensitivity function will be plotted.
#' @param calculate_criterion  Logical. Re-calculate the criterion value (maybe with a set of new tuning parameters to be sure of the globality of the maximum over the parameter space given the design)? It only assumes a continuous parameter space for the minimax and standardized maximin designs.  Defaults to \code{FALSE}. See 'Details'.
#' @param sens.control Control Parameters for Calculating the ELB. For details, see the function \code{\link{sens.control}}.
#' @param sens.minimax.control Control parameters to verify general equivalence theorem. For details, see \code{\link{sens.minimax.control}}.
#' If \code{NULL} (default), it will be set to the  tuning parameters used to create object \code{x}.
#' @param crt.minimax.control Control parameters to optimize the minimax or standardized maximin criterion at a given design over a \strong{continuous} parameter space.
#'  For details, see \code{\link{crt.minimax.control}}.
#' @param sens.bayes.control Control parameters to verify general equivalence theorem for the Bayesian optimal designs. For details, see \code{\link{sens.bayes.control}}. If \code{NULL} (default), it will be set to the  tuning parameters used to create object \code{x}.
#' @param crt.bayes.control Control parameters to optimize the integration in the Bayesian criterion at a given design over a \strong{continuous} parameter space. For details, see \code{\link{crt.bayes.control}}. If \code{NULL} (default), it will be set to the  tuning parameters used to create object \code{x}.
#'  If \code{NULL} (default), it will be set to the  tuning parameters used to create object \code{x}.
#' @param silent Do not print anything? Defaults to \code{TRUE}.
#' @param plot_3d Which package should be used to plot the sensitivity function for two-dimensional design space. Defaults to \code{plot_3d = "lattice"}.
#' Only applicable when \code{sensitivity = TRUE}.
#' @param evolution Plot Evolution? Defaults to \code{FALSE}.
#' @param ... Argument with no further use.
#' @seealso \code{\link{minimax}}, \code{\link{locally}}, \code{\link{robust}}
#' @details
#'
#' In addition to verifying the general equivalence theorem,
#'  this function makes it possible to re-calculated the criterion value
#'   for the output designs using a new set of tuning parameters, especially,
#'    a large value for \code{maxeval} in the function \code{\link{crt.minimax.control}}.
#'  This is useful for  minimax and standardized maximin optimal designs to assess
#'   the robustness of the
#'  criterion value with respect to different values of \code{maxeval}.
#'  To put it simple, for these designs, the user can re-calculate the
#'  criterion value (finds the global maximum over the parameter space given an output design in a minimax problem)
#'   with larger values for  \code{maxeval} in \code{\link{crt.minimax.control}}
#'  to be sure that the function \code{nloptr} finds global optima of the inner
#'  optimization problem over the parameter space using the default value
#'  (or the user-given value) of \code{maxeval}.
#'  If increasing the value of \code{maxeval} returns different criterion values,
#'  then the results can not be trusted and the algorithm should be repeated with a higher value for \code{maxeval}.
#' @export
plot.minimax <- function(x, 
                         iter = NULL,
                         sensitivity = TRUE,
                         calculate_criterion = FALSE,
                         sens.minimax.control = list(),
                         crt.minimax.control = list(),
                         sens.bayes.control = list(),
                         crt.bayes.control = list(),
                         sens.control = list(),
                         silent = TRUE,
                         plot_3d = c("lattice", "rgl"),
                         evolution = FALSE,
                         ...){
  if (!evolution & !sensitivity){
    warning("Both 'sensitivity' and 'evolution' set to be FALSE.\nNo action is done in plot function!")
    return(invisible(NULL))
  }
  #if (any(class(x) != c("list", "minimax"))) # 062020@seongho
  if (any(class(x) != c("minimax")))
    stop("'x' must be of class 'minimax'")

  ## to not be confused with design points
  obj <- x
  arg <- obj$arg
  if(is.null(iter))
    totaliter <- length(obj$evol) else
      totaliter <- iter
  if (totaliter > length(x$evol))
    stop("'iter' is larger than the maximum number of iterations")

  #cat("#### HERE HERE ####\n")

  if(x$method!="bayes"){
    #sens.minimax.control = sens.minimax.bayes.control
    #crt.minimax.control = crt.minimax.bayes.control
    if (calculate_criterion || sensitivity){
      if (is.null(sens.minimax.control)){
        sens.minimax.control <- arg$sens.minimax.control}
      else {
        sens.minimax.control <- do.call("sens.minimax.control", sens.minimax.control)
      }
      if (is.null(sens.control)){
        sens.control <- arg$sens.control}
      else {
        sens.control <- do.call("sens.control", sens.control)
      }
      if (is.null(crt.minimax.control)){
        crt.minimax.control <- arg$crt.minimax.control}
      else {
        crt.minimax.control <- do.call("crt.minimax.control", crt.minimax.control)
        if (arg$type == "minimax")
          crt.minimax.control$inner_space <- "continuous"
      }

      optim_starting <- function(fn, lower, upper, w, x, fixedpar, fixedpar_id,  npred){
        if (!arg$is.only.w)
          q1 <- c(x, w) else
            q1 <- w
          out <- optim2(fn = fn, lower = lower, upper = upper,
                        n_seg = sens.minimax.control$n_seg,
                        q = q1,
                        fixedpar = fixedpar, fixedpar_id = fixedpar_id,
                        npred= npred)
          minima <- out$minima
          counts <- out$counts
          return(list(minima =minima, counts = counts))
      }
      sens_varlist <-list(fixedpar = arg$fixedpar, fixedpar_id = arg$fixedpar_id,
                          npred = length(arg$lx),
                          crfunc_sens = arg$crfunc_sens,
                          lp_nofixed = arg$lp_nofixed,
                          up_nofixed = arg$up_nofixed,
                          plot_3d = plot_3d,
                          npar = arg$npar,
                          optim_starting = optim_starting,
                          fimfunc_sens = arg$FIM_sens,
                          Psi_x_minus_minimax = arg$Psi_funcs$Psi_x_minus_minimax,
                          Psi_x = arg$Psi_funcs$Psi_x,
                          Psi_xy = arg$Psi_funcs$Psi_xy, Psi_Mu = arg$Psi_funcs$Psi_Mu)

      sens_res <- sensminimax_inner(x = obj$evol[[totaliter]]$x, w = obj$evol[[totaliter]]$w,
                                    lx = arg$lx, ux = arg$ux,
                                    lp = arg$lp_nofixed, up = arg$up_nofixed,
                                    fimfunc = arg$FIM,
                                    sens.minimax.control = sens.minimax.control,
                                    sens.control = sens.control,
                                    type = arg$type,
                                    localdes = arg$localdes,
                                    plot_sens = TRUE,
                                    varlist = sens_varlist,
                                    calledfrom = "plot",
                                    npar = arg$npar,
                                    calculate_criterion = calculate_criterion,
                                    crt.minimax.control = crt.minimax.control,
                                    robpars = arg$robpars,
                                    plot_3d = plot_3d[1],
                                    silent = silent,
                                    calculate_sens = sensitivity)
    }

    #cat("#### HOWABOUT ####\n")

    if (evolution){
      ## extract evolution data from the object
      mean_cost <- sapply(1:totaliter, FUN = function(j)obj$evol[[j]]$mean_cost)
      min_cost <- sapply(1:totaliter, FUN = function(j)obj$evol[[j]]$min_cost)
      if (calculate_criterion)
        min_cost[totaliter] <- sens_res$crtval


      type <- obj$arg$type

      # plot setting
      legend_place <- "topright"
      legend_text <- c( "Best Imperialist", "Mean of Imperialists")
      line_col <- c("firebrick3", "blue4")
      if (type == "minimax")
        title1 <- "cost value"
      if (type == "standardized")
        title1 <- "minimum efficiency"
      if (type == "locally" || type == "robust")
        title1 <- "log determinant of inverse of FIM"
      if (type == "multiple_locally")
        title1 <- "criterion value"

      ylim = switch(type,
                    "minimax" = c(min(min_cost) - .07, max(mean_cost[1:totaliter]) + .2),
                    "standardized" = c(min(mean_cost[1:totaliter]) - .07, max( min_cost) + .2),
                    "locally" = c(min(min_cost) - .07, max(mean_cost[1:totaliter]) + .2),
                    "robust" = c(min(min_cost) - .07, max(mean_cost[1:totaliter]) + .2))

      PlotEffCost(from = 1,
                  to = (totaliter),
                  AllCost = min_cost, ##all criterion up to now (all cost function)
                  UserCost = NULL,
                  DesignType = type,
                  col = line_col[1],
                  xlab = "Iteration",
                  ylim = ylim,
                  lty = 1,
                  title1 = title1,
                  plot_main = TRUE)
      ICAMean_line <-  mean_cost[1:(totaliter)]
      lines(x = 1:(totaliter),
            y = ICAMean_line,
            col = line_col[2], type = "s", lty = 5)
      legend(x = legend_place,  legend = legend_text,lty = c(1,5, 3), col = line_col, xpd = TRUE, bty = "n")
    }

    #cat("####****#### HERE????? #####******#####\n")

  }else{ # bayes
    #sens.bayes.control = sens.minimax.bayes.control
    #crt.bayes.control = crt.minimax.bayes.control
    if (calculate_criterion || sensitivity){
      if (is.null(sens.bayes.control)){
        sens.bayes.control <- arg$sens.bayes.control }else {
          sens.bayes.control <- do.call("sens.bayes.control", sens.bayes.control)
        }
      if (is.null(sens.control)){
        sens.control <- arg$sens.control }else {
          sens.control <- do.call("sens.control", sens.control)
        }
      if (is.null(crt.bayes.control)){
        crt.bayes.control <- arg$crt.bayes.control
        Psi_x_bayes  <- arg$Psi_funcs$Psi_x_bayes
        Psi_xy_bayes  <- arg$Psi_funcs$Psi_xy_bayes
      } else {

        crt.bayes.control <- do.call("crt.bayes.control", crt.bayes.control)
        temp_psi <- create_Psi_bayes(type = arg$type, prior = arg$prior, FIM = arg$FIM, lp = arg$prior$lower,
                                     up = arg$prior$upper, npar = arg$npar,
                                     truncated_standard = arg$truncated_standard,
                                     const = arg$const, sens.bayes.control = sens.bayes.control,
                                     compound = arg$compound,
                                     method =  sens.bayes.control$method,
                                     user_sensfunc = arg$user_sensfunc)
        Psi_x_bayes  <- temp_psi$Psi_x_bayes
        Psi_xy_bayes  <- temp_psi$Psi_xy_bayes
      }

      vertices_outer <- make_vertices(lower = arg$lx, upper = arg$ux)
      sens_varlist <-list(npred = length(arg$lx),
                          # plot_3d = "lattice",
                          npar = arg$npar,
                          fimfunc_sens = arg$FIM_sens,
                          Psi_x_bayes  = Psi_x_bayes,
                          Psi_xy_bayes  = Psi_xy_bayes,
                          crfunc = arg$crfunc,
                          vertices_outer = vertices_outer)

      sens_res <- sensbayes_inner(x = obj$evol[[totaliter]]$x, w = obj$evol[[totaliter]]$w,
                                  lx = arg$lx, ux = arg$ux,
                                  fimfunc = arg$FIM,
                                  prior = arg$prior,
                                  sens.control = sens.control,
                                  sens.bayes.control = sens.bayes.control,
                                  crt.bayes.control = crt.bayes.control,
                                  type = arg$type,
                                  plot_3d = plot_3d[1],
                                  plot_sens = TRUE,
                                  const = arg$const,
                                  compound = arg$compound,### you dont need compund here
                                  varlist = sens_varlist,
                                  calledfrom =  "plot",
                                  npar = arg$npar,
                                  calculate_criterion = calculate_criterion,
                                  silent = silent,
                                  calculate_sens = sensitivity)
    }
    if (evolution){
      ## extract evolution data from the object
      mean_cost <- sapply(1:totaliter, FUN = function(j)obj$evol[[j]]$mean_cost)
      min_cost <- sapply(1:totaliter, FUN = function(j)obj$evol[[j]]$min_cost)
      if (calculate_criterion)
        min_cost[totaliter] <- sens_res$crtval


      type <- obj$arg$type

      # plot setting
      legend_place <- "topright"
      legend_text <- c( "Best Imperialist", "Mean of Imperialists")
      line_col <- c("firebrick3", "blue4")
      title1 <- "Bayesian criterion"
      ylim = switch(type, "bayesian_D" = c(min(min_cost) - .07, max(mean_cost[1:(totaliter)]) + .2))


      PlotEffCost(from = 1,
                  to = (totaliter),
                  AllCost = min_cost, ##all criterion up to now (all cost function)
                  UserCost = NULL,
                  DesignType = type,
                  col = line_col[1],
                  xlab = "Iteration",
                  ylim = ylim,
                  lty = 1,
                  title1 = title1,
                  plot_main = TRUE)
      ICAMean_line <-  mean_cost[1:(totaliter)]
      lines(x = 1:(totaliter),
            y = ICAMean_line,
            col = line_col[2], type = "s", lty = 5)
      legend(x = legend_place,  legend = legend_text,lty = c(1,5, 3), col = line_col, xpd = TRUE, bty = "n")
    }
  }

  #cat("#### ************** THERE **************#####\n")

  if(sensitivity || calculate_criterion)
    return(sens_res) else
      return(invisible(NULL))
}
######################################################################################################*
######################################################################################################*
#' Printing \code{minimax} Objects
#'
#' Print method for an object of class \code{minimax}.
#' 
#' @param x An object of class \code{minimax}.
#' @param ... Argument with no further use.
#' @export
#' @seealso \code{\link{minimax}}, \code{\link{locally}}, \code{\link{robust}}, \code{\link{bayes}}
print.minimax <- function(x, ...){

  if (any(class(x) != c("minimax")))
    stop("'x' must be of class 'minimax'")
  object <- x
  totaliter <- length(object$evol)
  type <- x$arg$type

  # 06202020@seongho
  flab = ""
  if(x$method=="locally")
    flab = "locally optimal designs"
  else if(x$method=="minimax")
    flab = "minimax optimal designs"
  else if(x$method=="robust")
    flab = "robust or optimum-on-average optimal designs"
  else if(x$method=="bayes")
    flab = "Bayesian optimal designs"

  cat("\nFinding ",flab,"\n")
  #cat("\nCall:\n",
  #    paste(deparse(x$call), sep = "\n", collapse = "\n"), "\n\n", sep = "")

  if(!is.null(x$call)){
    cat("\nCall:\n",
        paste(deparse(x$call), sep = "\n", collapse = "\n"), "\n\n", sep = "")
  }else{
    cat("\nCall:\n","FIM defined directly via the argument 'fimfunc'","\n\n",sep = "")
  }

  #cat("Optimal designs' profile:\n")
  tpos = seq(1,totaliter,length=min(10,totaliter))
  print(object$out[tpos,])
  #cat("")

  cat("\nOptimal designs (k=",x$arg$k,"):\n",sep="")
  cat(" ",print_xw_char(x = object$evol[[totaliter]]$x, w =  object$evol[[totaliter]]$w,
                       npred = length(object$arg$lx), is.only.w = object$arg$is.only.w,
                       equal_weight = object$arg$ICA.control$equal_weight)
      ,sep=""
  )
  cat("\n\n ICA iteration:", totaliter)
  cat("\n Criterion value: ", object$evol[[totaliter]]$min_cost)

  cat("\n Total number of function evaluations:", object$alg$nfeval)
  cat("\n Total number of successful local search moves:", object$alg$nlocal)
  cat("\n Total number of successful revolution moves:", object$alg$nrevol)

  cat("\n Convergence:", object$alg$convergence)

  if (object$arg$ICA.control$only_improve)
    cat("\n Total number of successful assimilation moves:", object$alg$nimprove)
  if (type == "minimax")
    cat( "\n Vector of maximum parameter values: ", object$evol[[totaliter]]$param)
  if (type == "standardized")
    cat( "\n Vector of minimum parameter values: ", object$evol[[totaliter]]$param)
  cat("\n CPU time:", object$arg$time[1], " seconds!\n")

  if (!is.null(object$evol[[totaliter]]$sens))
    print(object$evol[[totaliter]]$sens)

  return(invisible(NULL))
}

######################################################################################################*
######################################################################################################*
#' Printing \code{sensminimax} Objects
#'
#' Print method for an object of class \code{sensminimax}.
#' @param x An object of class \code{sensminimax}.
#' @param ... Argument with no further use.
#' @export
#' @seealso \code{\link{sensminimax}}, \code{\link{senslocally}}, \code{\link{sensrobust}}

print.sensminimax <- function(x,...){
  #if (any(class(x) != c("list", "sensminimax"))) # 06202020@seongho
  if (any(class(x) != c("sensminimax")))
    stop("'x' must be of class 'sensminimax'")

  #cat("#############************** SENSE HERE ################\n")
  #print(x)
  #print(names(x))
  #cat("################################ SENSE END ################################\n")

  #if(x$method!="bayes"){
    #cat("\n***********************************************************************")
    if (!is.null(x$max_deriv))
      cat("\n Maximum of the sensitivity function is ", x$max_deriv, "\n Efficiency lower bound (ELB) is ", x$ELB)
    if (!is.null(x$crtval))
      cat("\n Criterion value is ", x$crtval)
    if (x$type != "locally" & x$type != "robust"){
      cat("\n Verification required",x$time, "seconds!", "\n Adjust the control parameters in 'sens.minimax.control' ('n_seg') or in 'sens.bayes.control' for higher speed.", "\n\n")
    }else{
      cat("\n Verification required",x$time, "seconds!", "\n\n")
    }
  #}else{
  #  #cat( #"\n***********************************************************************")
  #  cat("\n Maximum of the sensitivity function is ", x$max_deriv, "\n Efficiency lower bound (ELB) is ", x$ELB,
  #    "\n Verification required",x$time, "seconds!",
  #    "\n Adjust the control parameters in 'sens.bayes.control' for higher speed\n\n")
    #   if (x$type == "minimax")
    #     optimchar <- "\nSet of all maxima over parameter space\n"
    #   if (x$type == "standardized")
    #     optimchar <- "\nSet of all minima over parameter space\n"
    #   cat("\nAnswering set:\n", answer, optimchar, optima, "\n")
    # }
    #
    # if (!is.null(x$crtval))
    #   cat("Criterion value found by 'nloptr':", x$crtval)
    #cat("***********************************************************************")
  #}

  return(invisible(NULL))
}

######################################################################################################*
######################################################################################################*
#' Returns Control Parameters for Optimizing Minimax Criteria Over The Parameter Space
#'
#'
#' The function \code{crt.minimax.control} returns a list of \code{\link[nloptr]{nloptr}} control parameters for optimizing the minimax criterion over the parameter space.\cr
#' The key tuning parameter for our application is \strong{\code{maxeval}.}
#' Its value should be increased when either the dimension or the size of the parameter space becomes larger
#'  to avoid pre-mature convergence in the inner optimization problem over the parameter space.
#' If the CPU time matters, the user should find an appropriate speed-accuracy trade-off  for her/his own design problem.
#'
#' @param x0 Vector of the starting values for the optimization problem (must be from the parameter space).
#' @param optslist A list. It will be passed to the argument \code{opts} of the function \code{\link[nloptr]{nloptr}}. See 'Details'.
#' @param ... Further arguments will be passed to \code{\link{nl.opts}} from package \code{\link[nloptr]{nloptr}}.
#' @importFrom nloptr nl.opts
#' @importFrom nloptr nloptr.print.options
#' @return A list of control parameters for the function \code{\link[nloptr]{nloptr}}.
#' @details
#'  Argument \code{optslist} will be passed to the argument \code{opts} of the function \code{\link[nloptr]{nloptr}}:
#'  \describe{
#'   \item{\code{stopval}}{Stop minimization when an objective value <= \code{stopval} is found. Setting \code{stopval} to \code{-Inf} disables this stopping criterion (default).}
#'   \item{\code{algorithm}}{Defaults to \code{NLOPT_GN_DIRECT_L}. DIRECT-L is a deterministic-search algorithm based on systematic division of the search domain into smaller and smaller hyperrectangles.}
#'   \item{\code{xtol_rel}}{Stop when an optimization step (or an estimate of the optimum) changes every parameter by less than \code{xtol_rel} multiplied by the absolute value of the parameter. Criterion is disabled if \code{xtol_rel} is non-positive. Defaults to \code{1e-5}.}
#'   \item{\code{ftol_rel}}{Stop when an optimization step (or an estimate of the optimum) changes the objective function value by less than \code{ftol_rel} multiplied by the absolute value of the function value. Criterion is disabled if \code{ftol_rel} is non-positive. Defaults to \code{1e-8}.}
#'   \item{\code{maxeval}}{Stop when the number of function evaluations exceeds \code{maxeval}. Criterion is disabled if \code{maxeval} is non-positive. Defaults to \code{1000}. See below.}
#' }
#'  A detailed explanation of all the options is shown by \code{nloptr.print.options()} in package \code{\link[nloptr]{nloptr}}.
#'
#' @export
#' @examples
#' crt.minimax.control(optslist = list(maxeval = 2000))
crt.minimax.control <- function (x0 = NULL,
                                 optslist = list(stopval = -Inf,
                                                 algorithm = "NLOPT_GN_DIRECT_L",
                                                 xtol_rel = 1e-6,
                                                 ftol_rel = 0,
                                                 maxeval = 1000), ...){

  optstlist2 <- do.call(c, list(optslist, list(...)))
  outlist <- suppressWarnings(nloptr::nl.opts(optstlist2))
  outlist["algorithm"] <- optslist$algorithm

  ## outlist has the defaut values of the nl.opts, when any component is null.
  # we play with that here
  if (is.null(optslist$algorithm))
    outlist$algorithm <- "NLOPT_GN_DIRECT_L"
  if (is.null(optslist$stopval))
    outlist$stopval<- -Inf
  if (is.null(optslist$xtol_rel))
    outlist$xtol_rel <- 1e-6
  if (is.null(optslist$ftol_rel))
    outlist$ftol_rel <- 0
  if (is.null(optslist$maxeval))
    outlist$maxeval <- 1000

  return(list(x0 = x0, optslist = outlist))
}
######################################################################################################*
######################################################################################################*
#' @title Returns Control Parameters for Verifying General Equivalence Theorem For Minimax Optimal Designs
#'
#'
#' @description
#' This function returns a list of control parameters that are used to find
#' the ``answering set'' for minimax and
#' standardized maximin designs.
#'  The answering set is required to  obtain the sensitivity (derivative) function in order to verify the optimality of
#'  a given design.
#'
#'
#' @param n_seg For a given design, the number of starting points in the local search to find all the local maxima of the minimax criterion over the parameter space is equal to \code{(n_seg + 1)^p}. Defaults to \code{6}.
#' Please increase its value when the parameter space is large. It is also applicable for standardized maximin designs. See 'Details' of \link{sens.minimax.control}.
#' @param merge_tol Merging tolerance. It is used  to  specify the elements of the answering set
#' by choosing only the local maxima (found by the local search) that are nearer to
#' the global maximum.  See 'Details' of \link{sens.minimax.control}. Defaults to \code{0.005}.
#' We advise to not change its default value because it has been successfully tested on many optimal design problems.
#' @return A list of control parameters for verifying the general equivalence
#'  theorem for minimax and standardized maximin optimal designs.
#' @details
#'  Given a design, an ``answering set'' is a subset of all the local optima
#'   of the optimality criterion over the parameter space.
#' Answering set is used to obtain the sensitivity function
#' of a minimax or standardized maximin criterion.
#'    Therefore, an invalid  answering set may result in a false
#'   sensitivity plot and ELB.
#'  Unfortunately, there is no theoretical rule on how to choose the number of elements of
#'   the answering set; and they  have to be found by trial and error.
#'  Given a design, the answering set for a minimax criterion is obtained as follows:
#'  \itemize{
#'  \item{Step 1: }{Find all the local maxima of the optimality criterion (minimax)  over the parameter space.
#'   For this purpose,  the parameter space is divided into \code{(n_seg + 1)^p} segments,
#'    where p is the number of unknown model parameters.
#'    Then, each boundary point of the resulted segments (intervals) is assigned to the argument
#'    \code{par} of the function \code{optim} in order to start a local search
#'     using the \code{"L-BFGS-B"} method.}
#'  \item{Step 2: }{Pick the ones nearest to the global minimum subject to a merging tolerance
#'   \code{merge_tol} (default \code{0.005}).}
#' }
#' Obviously, the answering set is a subset of all the local maxima over the parameter space (or local minima in case of standardized maximin criteria)
#' Therefore, it is very important to be able to find all the local maxima to create the true answering set with no missing elements.
#'  Otherwise, even when the design is optimal, the sensitivity (derivative) plot may not reveal its optimality.
#'
#'    Note that the minimax criterion (or standardized maximin criterion)
#'    is a multimodel function especially near the optimal design and
#'    this makes the job of finding all the locall maxima (minima) over the
#'    parameter space very complicated.
#'
#'
#' @export
#' @examples
#' sens.minimax.control()
#' sens.minimax.control(n_seg = 4)
sens.minimax.control <- function(n_seg = 6, merge_tol = .005){

  # the default value is tha same as the ones in the list, so no modification is
  if (!is.numeric(n_seg) || n_seg <= 0)
    stop("The value of 'n_seg' must be > 0")
  if (!is.numeric(merge_tol) || merge_tol <= 0)
    stop("The value of 'merge_tol' must be > 0")

  return(list(n_seg = n_seg, merge_tol = merge_tol))
}
######################################################################################################*
######################################################################################################*
# roxygen
#' @title Updating an Object of Class \code{minimax}
#'
#' @description  Runs the ICA optimization algorithm on an object of class \code{minimax} for more number of iterations  and updates the results.
#'
#' @param object An object of class \code{minimax}.
#' @param iter Number of iterations.
#' @param ... An argument of no further use.
#' @importFrom nloptr directL
#' @importFrom utils capture.output
#' @seealso \code{\link{minimax}}
#' @export
update.minimax <- function(object, iter, ...){
  if (all(class(object) != c("minimax")))
    stop("''object' must be of class 'minimax'")
  if (missing(iter))
    stop("'iter' is missing")

  #if(object$method!="bayes"){
  if(any(object$arg$type==c("D", "DPA", "DPM", "multiple", "user"))){
    bayes.update(object=object,iter=iter,...)
  }else{
    minimax.update(object=object,iter=iter,...)
  }
}

#' @importFrom utils capture.output
minimax.update <- function(object, iter, ...){ # 06212020@seongho
  # ... is an argument of no use. Only to match the generic update
  #if (all(class(object) != c("list", "minimax"))) # 06202020@seongho

  # blocked by 06212020@seongho
  #if (all(class(object) != c("minimax")))
  #    stop("''object' must be of class 'minimax'")
  #if (missing(iter))
  #  stop("'iter' is missing")

  arg <- object$arg
  ICA.control <- object$arg$ICA.control
  crt.minimax.control <- object$arg$crt.minimax.control
  sens.minimax.control <-  object$arg$sens.minimax.control
  sens.control <-  object$arg$sens.control
  evol <- object$evol
  evol.flag <- 0 # 1: updating, 0: not updating # 06212020@seongho
  #if (!arg$is.only.w)
  npred <- length(arg$lx) #else
  #    npred <- NA #dim(arg$x)[2]
  ## all fo the types for optim_on_average will be set to be equal to "robust"
  ## but the arg$type remains unchanged to be used in equivalence function!!
  # if( grepl("on_average", arg$type))
  #   type = "robust" else
  #     type <- arg$type
  type <- arg$type

  # warning: no arg$type must be used further

  if (type == "robust")
    npar <- dim(arg$param)[2] else
      npar <- length(arg$lp)
  if (ICA.control$equal_weight)
    w_equal <- rep(1/arg$k, arg$k)

  ###############################################################*
  ## multi_locally is the same as locally in update!

  if (type == "multiple_locally"){
    type <- "locally"
    ## rewuired for setting the title of plots
    multi_type <- TRUE
  }else
    multi_type <- FALSE

  # if (type == "multiple_minimax")
  #   type <- "minimax"

  if (!(type %in% c("minimax", "standardized", "locally", "robust")))
    stop("Bug: the type must be 'minimax' or 'standardized' or 'locally' or 'ave' in 'iterate.minimax\nset  'multiple_locally' to 'locally'")
  # because they have the same configuration. But we need to know the multi becasue of the verifying and plot methods!
  ##################################################################*

  # if (type == "locally")
  #   param_locally <- arg$up
  # if (type == "robust")
  #   param_set <- arg$robpars$parset


  ############################################################*
  ###finding if there is any fixed parameters.
  # only if type != "locally"
  #if (type != "locally" & control$inner_space != "vertices" & control$inner_space != "discrete"){
  # if (type != "locally" && type != "robust"){
  #   # here we search if one of the parameters are fixed. then we pass it to the optimization function in the inner problem because otherwise it may casue an error.
  #   any_fixed <- sapply(1:length(lp), function(i) lp [i] == up[i]) # is a vector
  #   if (any(any_fixed)){
  #     is_fixed <- TRUE
  #     fixedpar_id <- which(any_fixed)
  #     fixedpar <- lp[fixedpar_id]
  #     lp <- lp[-fixedpar_id]
  #     up <- up[-fixedpar_id]
  #     ## warning: lp and up are channged here if 'any_fix == TRUE'
  #   }else{
  #     fixedpar <- NA
  #     fixedpar_id <- NA
  #     is_fixed <- FALSE
  #   }
  # }else{
  #   fixedpar <- NA
  #   fixedpar_id <- NA
  #   is_fixed <- FALSE
  # }
  if(crt.minimax.control$inner_space == "discrete"){
    if(!is.na(arg$fixedpar))
      discrete_set <- crt.minimax.control$param_set[, -arg$fixedpar_id, drop = FALSE] else
        discrete_set <- crt.minimax.control$param_set
  }else
    discrete_set <-NULL
  ########################################################*

  ########################################################*
  # plot setting
  #plot_cost <- control$plot_cost
  #plot_sens <- control$plot_sens
  legend_place <- "topright"
  legend_text <- c( "Best Imperialist", "Mean of Imperialists")
  line_col <- c("firebrick3", "blue4")
  if (type == "minimax")
    title1 <- "cost value"
  if (type == "standardized")
    title1 <- "minimum efficiency"
  if (type == "locally" || type == "robust")
    title1 <-  "log determinant of inverse of FIM"
  if (multi_type)
    title1 <- "criterion value"
  ##################################################################*
  ## In last iteration the check functions should be applied??
  check_last <- ifelse(ICA.control$checkfreq == 0, FALSE, TRUE)

  # ##################################################################*
  # ### re-defimimg crfunc to handle fixed parameters.
  # crfunc <- arg$crfunc
  # if (is_fixed){
  #   crfunc2 <- function(param, q, fixedpar = NA, fixedpar_id = NA, npred){
  #     # if (any(!is.na(fixedpar))){
  #     #   if (any(is.na(fixedpar_id)))
  #     #     stop("'fixedpar' index is missing.")
  #     param_new <- rep(NA, length(param) + length(fixedpar))
  #     param_new[fixedpar_id] <- fixedpar
  #     param_new[-fixedpar_id] <- param
  #     param <- param_new
  #     #}
  #     out <- crfunc(param = param, q = q, npred = npred)
  #     return(out)
  #   }
  # }else{
  #   crfunc2 <- function(param, q, fixedpar = NA, fixedpar_id = NA, npred){
  #     # no use for fixedpar  and fixedpar_id = NA
  #     out <- crfunc(param = param, q = q, npred = npred)
  #     return(out)
  #   }
  # }
  # #####################################################################*

  ####################################################################*
  ### Psi as a function of x and x, y for plotting. Psi_x defined as minus psi to find the minimum
  ## Psi_x is mult-dimensional, x can be of two dimension.
  #
  #   Psi_x_minus <- function(x1, mu,  FIM,  x, w,  answering){
  #     ## mu and answering are only to avoid having another if when we want to check the maximum of sensitivity function
  #     Out <- arg$Psi_x(x1 = x1, mu =  mu, FIM = FIM,  x = x, w = w, answering = answering)
  #     return(-Out)
  #   }
  if(length(arg$lx) == 1)
    Psi_x_plot <-  arg$Psi_x ## for PlotPsi_x
  # it is necessary to distniguish between Psi_x for plotting and finding ELB becasue in plotting for models with two
  # explanatory variables the function should be defined as a function of x, y (x, y here are the ploints to be plotted)
  if(length(arg$lx) == 2)
    Psi_x_plot <- arg$Psi_xy
  #when length(lx) == 1, then Psi_x_plot = Psi_x
  #########################################################################*

  #########################################################################*
  # required for finding the answering set for verification
  #if (length(lp) <= 2)
  optim_starting <- function(fn, lower, upper, w, x, fixedpar, fixedpar_id,  npred){
    if (!arg$is.only.w)
      q1 <- c(x, w) else
        q1 <- w
      out <- optim2(fn = fn, lower = lower, upper = upper,
                    n_seg = sens.minimax.control$n_seg,
                    q = q1,
                    fixedpar = fixedpar, fixedpar_id = fixedpar_id,
                    npred= npred)
      minima <- out$minima
      counts <- out$counts
      return(list(minima =minima, counts = counts))
  }
  optim_func <- create_optim_func(type = type, lp_nofixed = arg$lp_nofixed, up_nofixed = arg$up_nofixed,
                                  crt.minimax.control = crt.minimax.control,
                                  discrete_set = discrete_set, robpars = arg$robpars,
                                  inipars = arg$inipars, is.only.w = arg$is.only.w)

  ################################################################################*
  ## x_id, w_id are the index of x and w in positions
  #cost_id is the index of
  ## in symmetric case the length of x_id can be one less than the w_id if the number of design points be odd!

  if (!arg$is.only.w){
    if (ICA.control$sym)
      x_id <- 1:floor(arg$k/2) else
        x_id <- 1:(arg$k * npred)

      if (!ICA.control$equal_weight)
        w_id <- (x_id[length(x_id)] + 1):length(arg$ld) else
          w_id <- NA
  }else{
    w_id <- 1:length(arg$ld)
    x_id <- NA
  }

  ###column index of cost in  matrix output of the inner problem
  if (type != "robust")
    CostColumnId <- length(arg$lp_nofixed) + 1 else
      CostColumnId <- dim(arg$robpars$parset)[2] + 1


  ## warning: not the lp withot fixed param

  ##########################################################################*
  ## whenever Calculate_Cost is used, the fixed_arg list should be passed to
  ## fixed argumnet for function Calculate_Cost
  fixed_arg = list(x_id = x_id,
                   w_id = w_id,
                   sym = ICA.control$sym ,
                   sym_point = ICA.control$sym_point,
                   CostColumnId = CostColumnId,
                   crfunc = arg$crfunc,
                   lp = arg$lp_nofixed, ## NULL for locally and optim_on_average
                   up = arg$up_nofixed, ## NULL for locally and optim_on_average
                   fixedpar = arg$fixedpar,
                   fixedpar_id = arg$fixedpar_id,
                   optim_func = optim_func,
                   npred = npred,
                   type = type,
                   equal_weight = ICA.control$equal_weight,
                   k = arg$k,
                   Calculate_Cost = Calculate_Cost_minimax,
                   is.only.w = arg$is.only.w)

  if (type == "robust")
    fixed_arg$parset <- arg$robpars$parset

  ## for sensitivity checking
  sens_varlist <-list(fixedpar = arg$fixedpar, fixedpar_id = arg$fixedpar_id,
                      npred = npred,
                      crfunc_sens = arg$crfunc_sens,
                      lp_nofixed = arg$lp_nofixed,
                      up_nofixed = arg$up_nofixed,
                      plot_3d = "lattice",
                      npar = arg$npar,
                      optim_starting = optim_starting,
                      fimfunc_sens = arg$FIM_sens,
                      Psi_x_minus_minimax = arg$Psi_funcs$Psi_x_minus_minimax, Psi_x = arg$Psi_funcs$Psi_x,
                      Psi_xy = arg$Psi_funcs$Psi_xy, Psi_Mu = arg$Psi_funcs$Psi_Mu,
                      is.only.w = arg$is.only.w)
  ############################################################################*

  ############################################################################*
  # Initialization when evol is NULL
  ############################################################################*
  if (is.null(evol)){
    evol.flag = 0
    ## set the old seed if call is from minimax
    if (!is.null(ICA.control$rseed))
      set.seed(ICA.control$rseed)

    msg <- NULL
    revol_rate <- ICA.control$revol_rate
    maxiter <- iter
    totaliter <- 0
    #evol <- list()
    min_cost <- c() ## cost of the best imperialists
    mean_cost <- c() ## mean cost of all imperialists
    check_counter <- 0 ## counter to count the check
    total_nlocal  <- 0 ## total number of successful local search
    if (!ICA.control$lsearch)
      total_nlocal <- NA
    total_nrevol <- 0 ## total number of successful revolution
    total_nimprove <- 0 ##total number of improvements due to assimilation
    prev_time <- 0
    ############################################## Initialization for ICA
    InitialCountries <- GenerateNewCountry(NumOfCountries = ICA.control$ncount,
                                           lower = arg$ld,
                                           upper = arg$ud,
                                           sym = ICA.control$sym,
                                           w_id = w_id,
                                           x_id = x_id,
                                           npred= npred,
                                           equal_weight = ICA.control$equal_weight,
                                           is.only.w = arg$is.only.w)

    if (!is.null(arg$initial))
      InitialCountries[1:dim(arg$initial)[1], ] <- arg$initial
    InitialCost <- vector("double", ICA.control$ncount)
    temp <- fixed_arg$Calculate_Cost(mat = InitialCountries, fixed_arg = fixed_arg)
    total_nfeval <-  temp$nfeval
    InitialCost <-  temp$cost
    inparam <- temp$inner_optima
    ## waring inparam for optim_on_average does not have any meaning!
    temp <- NA # safety
    ##Now we should sort the initial countries with respect to their initial cost
    SortInd <- order(InitialCost)
    InitialCost <- InitialCost[SortInd] # Sort the cost in assending order. The best countries will be in higher places
    InitialCountries <- InitialCountries[SortInd,, drop = FALSE] #  Sort the population with respect to their cost. The best country is in the first column
    inparam <- inparam[SortInd, , drop = FALSE]
    # creating empires
    Empires <- CreateInitialEmpires(sorted_Countries = InitialCountries,
                                    sorted_Cost = InitialCost,
                                    Zeta = ICA.control$zeta,
                                    NumOfInitialImperialists = ICA.control$nimp,
                                    NumOfAllColonies = (ICA.control$ncount - ICA.control$nimp),
                                    sorted_InnerParam = inparam)
    best_imp_id<- 1 ## the index of list in which best imperialists is in.
    ########################################################################*
  }
  ##########################################################################*

  ##########################################################################*
  # when we are updating the object for more number of iterations
  ##########################################################################*
  if (!is.null(evol)){
    evol.flag = 1
    ## reset the seed!
    if (exists(".Random.seed")){
      GlobalSeed <- get(".Random.seed", envir = .GlobalEnv)
      #if you call directly from update and not minimax!
      on.exit(assign(".Random.seed", GlobalSeed, envir = .GlobalEnv))
    }

    msg <- object$best$msg
    prev_iter <- length(evol) ##previous number of iterationst
    maxiter <- iter + prev_iter
    totaliter <- prev_iter
    mean_cost <- sapply(1:(totaliter), FUN = function(j) evol[[j]]$mean_cost)
    min_cost <- sapply(1:(totaliter), FUN = function(j) evol[[j]]$min_cost)
    Empires <- object$empires
    prev_time <- arg$time

    check_counter <- arg$updating$check_counter
    total_nfeval <- object$alg$nfeval
    total_nlocal <- object$alg$nlocal
    total_nrevol <- object$alg$nrevol
    total_nimprove <- object$alg$nimprove

    imp_cost <- round(sapply(object$empires, "[[", "ImperialistCost"), 12)
    best_imp_id<- which.min(imp_cost)
    revol_rate <-  arg$updating$revol_rate
    ##updating the random seed
    if (!is.null(ICA.control$rseed)){
      do.call("RNGkind",as.list(arg$updating$oldRNGkind))  ## must be first!
      assign(".Random.seed", arg$updating$oldseed , .GlobalEnv)
    }
  }
  ##########################################################################*
  space_size <- arg$ud - arg$ld
  continue = TRUE

  ###########################################################################*
  ### start of the while loop until continue == TRUE
  ###########################################################################*
  while (continue == TRUE){
    totaliter <- totaliter + 1
    check_counter <- check_counter + 1
    # if (totaliter == 1058)
    #   browser()
    revol_rate <- ICA.control$damp * revol_rate
    ## revolution rate is increased by damp ration in every iter

    #########################################################################*
    ################################################################# for loop over all empires[ii]
    for(ii in 1:length(Empires)){

      ########################################## local search is only for point!
      if (ICA.control$lsearch){


        LocalSearch_res <- LocalSearch(TheEmpire =  Empires[[ii]],
                                       lower = arg$ld,
                                       upper = arg$ud,
                                       l = ICA.control$l,
                                       fixed_arg = fixed_arg)
        Empires[[ii]] <- LocalSearch_res$TheEmpire
        total_nfeval <- total_nfeval + LocalSearch_res$nfeval
        total_nlocal <- total_nlocal + LocalSearch_res$n_success
      }
      ###################################################################*

      ############################################################## Assimilation
      temp5 <- AssimilateColonies2(TheEmpire = Empires[[ii]],
                                   AssimilationCoefficient = ICA.control$assim_coeff,
                                   VarMin = arg$ld,
                                   VarMax = arg$ud,
                                   ExceedStrategy = "perturbed",
                                   sym = ICA.control$sym,
                                   AsssimilationStrategy = ICA.control$assim_strategy,
                                   MoveOnlyWhenImprove = ICA.control$only_improve,
                                   fixed_arg = fixed_arg,
                                   w_id = w_id,
                                   equal_weight = ICA.control$equal_weight)
      ##Warning: in this function the colonies position are changed but the imperialist and the
      ##cost functions of colonies are not updated yet!
      ##they will be updated after revolution
      Empires[[ii]] <- temp5$TheEmpire
      total_nfeval <- total_nfeval + temp5$nfeval
      total_nimprove <-  total_nimprove + temp5$nimprove
      ##########################################################################*

      ############################################################### Revolution
      temp4 <- RevolveColonies(TheEmpire = Empires[[ii]],
                               RevolutionRate = revol_rate,
                               NumOfCountries = ICA.control$ncount,
                               lower = arg$ld,
                               upper = arg$ud,
                               sym = ICA.control$sym,
                               sym_point = ICA.control$sym_point,
                               fixed_arg = fixed_arg,
                               w_id = w_id,
                               equal_weight = ICA.control$equal_weight)
      Empires[[ii]] <- temp4$TheEmpire
      total_nrevol <- total_nrevol + temp4$nrevol
      total_nfeval <- total_nfeval + temp4$nfeval
      ############################################################*
      Empires[[ii]] <- PossesEmpire(TheEmpire = Empires[[ii]])

      ##after updating the empire the total cost should be updated
      ## Computation of Total Cost for Empires
      Empires[[ii]]$TotalCost <- Empires[[ii]]$ImperialistCost + ICA.control$zeta * mean(Empires[[ii]]$ColoniesCost)

    }
    ############################################################ end of the loop for empires [[ii]]
    ###############################################################################################*

    #################################################### Uniting Similiar Empires
    if (length(Empires)>1){

      Empires <- UniteSimilarEmpires(Empires = Empires,
                                     Zeta = ICA.control$zeta,
                                     UnitingThreshold = ICA.control$uniting_threshold,
                                     SearchSpaceSize = space_size)
    }
    ############################################################################*
    # zeta is necessary to update the total cost!
    Empires <- ImperialisticCompetition(Empires = Empires, Zeta = ICA.control$zeta)

    ############################################################## save the seed
    # we get the seed here because we dont know if in cheking it wil be chaned
    #we save the seed when we exit the algorithm
    oldseed <- get(".Random.seed", envir = .GlobalEnv)
    oldRNGkind <- RNGkind()
    ############################################################################*
    ############################################################################*
    # extracing the best emperor and its position
    imp_cost <- round(sapply(Empires, "[[", "ImperialistCost"), 12)
    min_cost[totaliter] <- switch(type, "minimax" = min(imp_cost), "standardized" = -min(imp_cost),
                                  "locally" =  min(imp_cost), "robust" = min(imp_cost))
    mean_cost[totaliter] <- switch(type, "minimax" = mean(imp_cost), "standardized" = -mean(imp_cost),
                                   "locally" = mean(imp_cost), "robust" = mean(imp_cost))

    best_imp_id <- which.min(imp_cost) ## which list contain the best imp
    if (!ICA.control$equal_weight)
      w <- Empires[[best_imp_id]]$ImperialistPosition[, w_id] else
        w <- w_equal
    if (!arg$is.only.w)
      x <- Empires[[best_imp_id]]$ImperialistPosition[, x_id] else
        x <- arg$only_w_varlist$x
    inparam <- Empires[[best_imp_id]]$ImperialistInnerParam
    if (length(arg$lp_nofixed)==1)
      inparam <- t(inparam)


    ##modifying the answering set if there is any fixed parameters.
    ## does not applicable for locally and optim_on_average
    if (any(!is.na(arg$fixedpar))){
      fix_inparam <- c(arg$fixedpar, inparam)
      NumOfParam <- 1:length(fix_inparam)
      inparam <- fix_inparam[order( c(arg$fixedpar_id, setdiff(NumOfParam, arg$fixedpar_id)))]
    }

    if (ICA.control$sym){
      x_w <- ICA_extract_x_w(x = x, w = w, sym_point = ICA.control$sym_point)
      x <- x_w$x
      w <- x_w$w
    }
    ##sort Point

    if (!arg$is.only.w){
      # do not sort if you have only weights because they correspond the points
      if (npred == 1){
        w <- w[order(x)]
        x <- sort(x)
      }
    }
    ############################################################################*

    ################################################################ print trace
    if (ICA.control$trace){
      # if (type != "locally" && type != "robust")
      #   cat("\nICA iter:", totaliter, "\nDesign Points:\n", x, "\nWeights: \n", w,
      #       "\nCriterion value: ", min_cost[totaliter], "\nparam: ",
      #       inparam,"\n") else
      #         cat("\nICA iter:", totaliter, "\nDesign Points:\n", x, "\nWeights: \n", w,
      #             "\nbest criterion value: ", min_cost[totaliter],"\n")

      if (!arg$is.only.w)
        cat("\nIteration:", totaliter, "\nDesign Points:\n", x, "\nWeights: \n", w,
            "\nCriterion value: ", min_cost[totaliter],
            "\nTotal number of function evaluations:", total_nfeval, "\nTotal number of successful local search moves:", total_nlocal,
            "\nTotal number of successful revolution moves:", total_nrevol, "\n") else
              cat("\nIteration:", totaliter, "\nWeights: \n", w,
                  "\nCriterion value: ", min_cost[totaliter],
                  "\nTotal number of function evaluations:", total_nfeval, "\nTotal number of successful local search moves:", total_nlocal,
                  "\nTotal number of successful revolution moves:", total_nrevol, "\n")

      if (ICA.control$only_improve)
        cat("Total number of successful assimilation moves:", total_nimprove, "\n")
      if (type == "minimax")
        cat( "Vector of maximum parameter values: ", inparam,"\n")
      if (type == "standardized")
        cat( "Vector of minimum parameter values: ", inparam,"\n")
    }
    ############################################################################*

    if ( min_cost[totaliter] == 1e-24)
      warning("Computational issue! maybe the design is singular!\n")

    ################################################################### continue
    if (totaliter ==  maxiter){
      continue <- FALSE
      convergence = "Maximum_Iteration"
    }
    if(length(Empires) == 1 && ICA.control$stop_rule == "one_empire"){
      continue <- FALSE
      convergence = "one_empire"
    }
    ## the continue also can be changed in check
    ############################################################################*

    ################################################################################# plot_cost
    if (ICA.control$plot_cost) {
      #ylim for efficiency depends on the criterion type because
      ylim = switch(type,
                    "minimax" = c(min(min_cost) - .07, max(mean_cost[1:(totaliter)]) + .2),
                    "standardized" = c(min(mean_cost[1:(totaliter)]) - .07, max( min_cost) + .2),
                    "locally" = c(min(min_cost) - .07, max(mean_cost[1:(totaliter)]) + .2))
      PlotEffCost(from = 1,
                  to = (totaliter),
                  AllCost = min_cost, ##all criterion up to now (all cost function)
                  UserCost = NULL,
                  DesignType = type,
                  col = line_col[1],
                  xlab = "Iteration",
                  ylim = ylim,
                  lty = 1,
                  title1 = title1,
                  plot_main = TRUE)
      ICAMean_line <-  mean_cost[1:(totaliter)]
      lines(x = 1:(totaliter),
            y = ICAMean_line,
            col = line_col[2], type = "s", lty = 5)
      legend(x = legend_place,  legend = legend_text,lty = c(1,5, 3), col = line_col, xpd = TRUE, bty = "n")
    }
    ############################################################################*

    ####################################################################################*
    #check the equivalence theorem and find ELB
    ####################################################################################*
    ## we check the quvalence theorem in the last iteration anyway. but we may not plot it.
    if (check_counter == ICA.control$checkfreq || (check_last && !continue)){
      check_counter <- 0
      if (arg$ICA.control$trace){
        #cat("\n*********************************************************************")
        if (!continue)
          cat("\nOptimization is done!\n")
        cat("Requesting design verification by the general equivalence theorem\n")
      }
      # if (type == "robust")
      #   type1 <- "locally" else
      #     type1 <- type
      ## Note: we pass the localdes here but we dont use it
      sens_res <- sensminimax_inner(x = x, w = w, lx = arg$lx, ux = arg$ux, lp = arg$lp_nofixed, up = arg$up_nofixed,
                                    fimfunc = arg$FIM,
                                    sens.minimax.control = sens.minimax.control,
                                    sens.control = sens.control,
                                    #nloptr.control.sens = nloptr.control.sens,
                                    type = type, localdes = NULL, plot_sens = ICA.control$plot_sens,
                                    varlist = sens_varlist, calledfrom = "iter",
                                    npar = arg$npar,
                                    calculate_criterion = FALSE,
                                    robpars = arg$robpars,
                                    plot_3d = arg$plot_3d,
                                    silent = !arg$ICA.control$trace)


      ##########################################################################*
      GE_confirmation <- ( sens_res$ELB >= ICA.control$stoptol)
      # print trace that is related to checking
      # if (ICA.control$trace)
      #   cat("maximum of sensitivity:", sens_res$max_deriv, "\nefficiency lower bound (ELB):", sens_res$ELB, "\n")
      if (GE_confirmation && ICA.control$stop_rule == "equivalence"){
        continue <- FALSE
        convergence <- "equivalence"
      }
    }else
      sens_res <- NULL
    # max_deriv <- answering <- answering_cost <-all_optima <- all_optima_cost  <- mu <- ELB <- NA
    # if (type == "locally" || type == "robust"){
    #   answering <- NA # now we dont need answering. We required it before for checking so we set it to NA
    #   mu <- 1
    # }
    ####################################################################### end of check
    ####################################################################### save
    # evol[[totaliter]] <- list(iter = totaliter,
    #                           x = x,
    #                           w = w,
    #                           min_cost = min_cost[totaliter],
    #                           mean_cost = mean_cost[totaliter],
    #                           all_optima = sens_res$all_optima,
    #                           all_optima_cost = sens_res$all_optima_cost,
    #                           answering = sens_res$answering,
    #                           answering_cost = sens_res$answering_cost,
    #                           mu = sens_res$mu,
    #                           max_deriv = sens_res$max_deriv,
    #                           ELB = sens_res$ELB)
    evol[[totaliter]] <- list(iter = totaliter, x = x, w = w, min_cost = min_cost[totaliter], mean_cost = mean_cost[totaliter], sens = sens_res)

    if (type != "locally" && type != "robust"){
      evol[[totaliter]]$param = inparam
    } else
      evol[[totaliter]]$param = NA
    ############################################################################*

    ################################################################ print trace
    # if (ICA.control$trace){
    #   cat("total local search:", total_nlocal, "\n")
    #   cat("total revolution:", total_nrevol, "\n")
    #   if (ICA.control$only_improve)
    #     cat("total improve:", total_nimprove, "\n")
    # }
    ############################################################################*
  }
  ##############################################################################*
  ### end of the while loop over continue == TRUE
  ##############################################################################*

  if (!ICA.control$only_improve)
    total_nimprove <- NA

  #if (ELB >= control$stoptol && control$stop_rule == "equivalence")
  #  convergence = "equivalence" else

  ##############################################################################*
  # check the appropriateness of the maxeval
  # if (type != "locally" & type != "robust" & control$inner_space == "continuous"){
  #   if (control$check_inner_maxeval){
  #     check_temp <- check_maxeval(fn = crfunc2, lower = lp, upper = up, maxeval = control$inner_maxeval,
  #                                 fixedpar = fixedpar, fixedpar_id = fixedpar_id, npred = npred, q = c(x, w))
  #     msg <- check_temp$msg
  #   }else
  #     msg <- NULL
  # }

  ##################*
  msg <- NULL
  ##############################################################################*

  ######################################################################## saving
  ## we add the following to arg becasue dont want to document it in Rd files
  # updating parameters
  object$arg$updating$check_counter <- check_counter
  object$arg$updating$oldseed <- oldseed
  object$arg$updating$oldRNGkind <- oldRNGkind
  object$arg$updating$revol_rate = revol_rate ## different from revolrate
  object$evol <- evol
  object$empires <- Empires

  if(evol.flag==1){
    dout = NULL
    fout = NULL
    fiter = length(object$evol)
    if(fiter>0){
      tout = c()
      for(i in 1:fiter){
        sout = object$evol[[i]]
        tout = rbind(tout,c(i,sout$x,sout$w,sout$min_cost,sout$mean_cost))
      }
      dout = as.data.frame(tout)
      if(length(sout$x)==length(sout$w)){
        dimnames(dout)[[2]] = c("iter",paste("x",1:object$arg$k,sep=""),paste("w",1:object$arg$k,sep=""),"min_cost","mean_cost")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx = c()
        for(i in 1:tlen){
          tdimx = c(tdimx,paste(paste("x",i,sep=""),1:object$arg$k,sep=""))
        }
        dimnames(dout)[[2]] = c("iter",tdimx,paste("w",1:object$arg$k,sep=""),"min_cost","mean_cost")
      }
      # extract sens outcomes
      sout = object$evol[[fiter]]
      tsens = capture.output(sout$sens)
      tpos.max = grep("Maximum",tsens)
      tpos.elb = grep("ELB",tsens)
      tpos.time = grep("Verification",tsens)
      tmax = NA
      telb = NA
      ttime = NA
      if(length(tpos.max)>0){
        tmax = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.max]),"is")[[1]][2])
      }
      if(length(tpos.elb)>0){
        telb = as.numeric(strsplit(gsub("\\s+","",tsens[tpos.elb]),"is")[[1]][2])
      }
      if(length(tpos.time)>0){
        ttime = as.numeric(strsplit(gsub("seconds!","",gsub("\\s+","",tsens[tpos.time])),"required")[[1]][2])
      }
      t2out = c(fiter,sout$x,sout$w,sout$min_cost,sout$mean_cost,tmax,telb,ttime)
      fout = as.data.frame(t(t2out))
      #dimnames(fout)[[2]] = c("iter",paste("x",1:object$arg$k,sep=""),paste("w",1:object$arg$k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      if(length(sout$x)==length(sout$w)){
        dimnames(fout)[[2]] = c("iter",paste("x",1:object$arg$k,sep=""),paste("w",1:object$arg$k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }else{
        tlen = length(sout$x)/length(sout$w)
        tdimx2 = c()
        for(i in 1:tlen){
          tdimx2 = c(tdimx2,paste(paste("x",i,sep=""),1:object$arg$k,sep=""))
        }
        dimnames(fout)[[2]] = c("iter",tdimx2,paste("w",1:object$arg$k,sep=""),"min_cost","mean_cost","max_sens","elb","time_sec")
      }
    }

    object$out = dout
    #out$out2 = out$evol
    object$design = fout
  }

  object$alg <- list(
    nfeval = total_nfeval,
    nlocal = total_nlocal,
    nrevol = total_nrevol,
    nimprove = total_nimprove,
    convergence = convergence)
  #msg = msg

  ## so object is 'res', 'arg' and 'evol'
  ## arg has a list named update as well
  ###### end of saving
  ##############################################################################*
  object$arg$time <- proc.time() - arg$time_start + prev_time
  return(object)
}
######################################################################################################*
######################################################################################################*

Try the ICAOD package in your browser

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

ICAOD documentation built on Oct. 23, 2020, 6:40 p.m.