# File src/library/stats/R/nlm.R # Part of the R package, https://www.R-project.org # # Copyright (C) 1995-2023 The R Core Team # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # A copy of the GNU General Public License is available at # https://www.R-project.org/Licenses/ nlm <- function(f, p, ..., hessian=FALSE, typsize=rep(1,length(p)), fscale=1, print.level=0, ndigit=12, gradtol=1e-6, stepmax=max(1000 * sqrt(sum((p/typsize)^2)), 1000), steptol=1e-6, iterlim=100, check.analyticals=TRUE) { print.level <- as.integer(print.level) if(print.level < 0 || print.level > 2) stop("'print.level' must be in {0,1,2}") ## msg is collection of bits, i.e., sum of 2^k (k = 0,..,4): msg <- (1 + c(8,0,16))[1+print.level] if(!check.analyticals) msg <- msg + (2 + 4) .External2(C_nlm, function(x) f(x, ...), p, hessian, typsize, fscale, msg, ndigit, gradtol, stepmax, steptol, iterlim) } optimize <- function(f, interval, ..., lower=min(interval), upper=max(interval), maximum=FALSE, tol=.Machine$double.eps^0.25) { if(maximum) { val <- .External2(C_do_fmin,function(arg) -f(arg, ...), lower, upper, tol) list(maximum = val, objective = f(val, ...)) } else { val <- .External2(C_do_fmin, function(arg) f(arg, ...), lower, upper, tol) list(minimum = val, objective = f(val, ...)) } } ##nice to the English (or rather the Scots) optimise <- optimize ## FIXME? have the 4 cases ## Sig \in {NULL, -1 , 0, 1 } -- with default 0 ---> ## extendInt ( yes, downX, no, upX ) -- with default "no" ## crossing (extend, down, free, up ) -- with default "free" uniroot <- function(f, interval, ..., lower = min(interval), upper = max(interval), f.lower = f(lower, ...), f.upper = f(upper, ...), extendInt = c("no", "yes", "downX", "upX"), check.conv = FALSE, tol = .Machine$double.eps^0.25, maxiter = 1000, trace = 0) { if(!missing(interval) && length(interval) != 2L) stop("'interval' must be a vector of length 2") if(!is.numeric(lower) || !is.numeric(upper) || lower >= upper) stop("lower < upper is not fulfilled") if(is.na(f.lower)) stop("f.lower = f(lower) is NA") if(is.na(f.upper)) stop("f.upper = f(upper) is NA") Sig <- switch(match.arg(extendInt), "yes" = NULL, "downX"= -1, "no" = 0, "upX" = 1, stop("invalid 'extendInt'; please report")) ## protect against later 0 * Inf |--> NaN and Inf * -Inf. truncate <- function(x) pmax.int(pmin(x, .Machine$double.xmax), -.Machine$double.xmax) f.low. <- truncate(f.lower) f.upp. <- truncate(f.upper) doX <- ( is.null(Sig) && f.low. * f.upp. > 0 || is.numeric(Sig) && (Sig*f.low. > 0 || Sig*f.upp. < 0)) if(doX) { ## extend the interval = [lower, upper] if(trace) cat(sprintf("search in [%g,%g]%s", lower, upper, if(trace >= 2)"\n" else " ... ")) Delta <- function(u) 0.01* pmax(1e-4, abs(u)) it <- 0L ## Two cases: if(is.null(Sig)) { ## case 1) 'Sig' unspecified --> extend (lower, upper) at the same time delta <- Delta(c(lower,upper)) while(isTRUE(f.lower*f.upper > 0) && any(iF <- is.finite(c(lower,upper)))) { if((it <- it + 1L) > maxiter) stop(gettextf("no sign change found in %d iterations", it-1), domain=NA) if(iF[1]) { ol <- lower; of <- f.lower if(is.na(f.lower <- f(lower <- lower - delta[1], ...))) { lower <- ol; f.lower <- of; delta[1] <- delta[1]/4 } } if(iF[2]) { ol <- upper; of <- f.upper if(is.na(f.upper <- f(upper <- upper + delta[2], ...))) { upper <- ol; f.upper <- of; delta[2] <- delta[2]/4 } } if(trace >= 2) cat(sprintf(" .. modified lower,upper: (%15g,%15g)\n", lower,upper)) delta <- 2 * delta } } else { ## case 2) 'Sig' specified --> typically change only *one* of lower, upper ## make sure we have Sig*f(lower) <= 0 and Sig*f(upper) >= 0: delta <- Delta(lower) while(isTRUE(Sig*f.lower > 0)) { if((it <- it + 1L) > maxiter) stop(gettextf("no sign change found in %d iterations", it-1), domain=NA) f.lower <- f(lower <- lower - delta, ...) if(trace >= 2) cat(sprintf(" .. modified lower: %g\n", lower)) delta <- 2 * delta } delta <- Delta(upper) while(isTRUE(Sig*f.upper < 0)) { if((it <- it + 1L) > maxiter) stop(gettextf("no sign change found in %d iterations", it-1), domain=NA) f.upper <- f(upper <- upper + delta, ...) if(trace >= 2) cat(sprintf(" .. modified upper: %g\n", upper)) delta <- 2 * delta } } if(trace && trace < 2) cat(sprintf("extended to [%g, %g] in %d steps\n", lower, upper, it)) } if(!isTRUE(sign(f.lower) * sign(f.upper) <= 0)) stop(if(doX) "did not succeed extending the interval endpoints for f(lower) * f(upper) <= 0" else "f() values at end points not of opposite sign") if(doX && it) { # need update (at least one) f.low. <- truncate(f.lower) f.upp. <- truncate(f.upper) } if(check.conv) { val <- tryCatch(.External2(C_zeroin2, function(arg) f(arg, ...), lower, upper, f.low., f.upp., tol, as.integer(maxiter)), warning = function(w)w) if(inherits(val, "warning")) stop("convergence problem in zero finding: ", conditionMessage(val)) } else { val <- .External2(C_zeroin2, function(arg) f(arg, ...), lower, upper, f.low., f.upp., tol, as.integer(maxiter)) } iter <- as.integer(val[2L]) if(iter < 0) { (if(check.conv) stop else warning)( sprintf(ngettext(maxiter, "_NOT_ converged in %d iteration", "_NOT_ converged in %d iterations"), maxiter), domain = NA) iter <- maxiter } if(doX) iter <- iter + it else it <- NA_integer_ list(root = val[1L], f.root = f(val[1L], ...), iter = iter, init.it = it, estim.prec = val[3L]) }## uniroot()