blob: 8623bf922bea851f92f3cba60e947e67e2d7ce16 [file] [log] [blame]
# File src/library/stats/R/nlm.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2013 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))
}
## this might have names
if(!isTRUE(as.vector(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(check.conv) {
val <- tryCatch(.External2(C_zeroin2, function(arg) f(arg, ...),
lower, upper, f.lower, f.upper,
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.lower, f.upper,
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()