#' Iterative Cyclic (Coordinate) Update
#'
#' @param fun.loss Scalar loss function (minimization objective), its signature
#'  is \code{function(params)} and return a scalar.
#' @param fun.update compute new parameter (parameter block) for the \code{index}
#'  parameter (block) in \code{params}, the function signature is
#'  \code{function(params, index)} and returns a parameter block corresponding
#'  to \code{fun.getElement(params, index)}
#' @param params initial paramiters, a.k.a. start position
#' @param indices parameter index set used with \code{[[<-} and passed to
#'  \code{fun.update}
#' @param fun.sample computes a permutation of indices. If the parameters
#'  should not be permuted use \code{identity}.
#' @param max.iter maximum number of parameter update cycles
#' @param eps small constant used in break conditions
#' @param callback function invoked for each iteration (including iteration 0)
#'  with the signature \code{function(iter, params)}.
#'
#' @example inst/examples/ICU.R
#'
#' @export
ICU <- function(fun.loss, fun.update, params,
    indices = base::seq_along(params),
    fun.sample = base::sample,
    max.iter = 50L,
    eps = .Machine$double.eps,
    callback = NULL
) {
    # Compute initial loss
    loss <- fun.loss(params)

    # Call callback for with initial parameters
    if (is.function(callback)) callback(0L, params)

    # iteration loop of parameter update cycles
    for (iter in seq_len(max.iter)) {
        # Random order parameter update cycle
        for (index in fun.sample(indices)) {
            params[[index]] <- fun.update(params, index)
        }

        # Call callback after each update cycle
        if (is.function(callback)) callback(iter, params)

        # recompute loss for brack condition
        loss.last <- loss
        loss <- fun.loss(params)

        # and check break condition
        if (abs(loss.last - loss) < eps) {
            break
        }
   }

    params
}
