Nothing
bfgs1run <- function(fn, gr, x0, H0 = NULL, maxit = 1000, fvalquit = -Inf, normtol = 1e-06, xnormquit = Inf,
evaldist = 1e-04, ngrad = 0, scale = 1, strongwolfe = 0, wolfe1 = 1e-04, wolfe2 = 0.5, quitLSfail = TRUE,
prtlevel = 1) {
n <- length(x0)
x0 <- as.matrix(x0)
iter <- 0
# Control parameter checking
if (is.null(H0))
H0 <- diag(1, n)
if (ngrad == 0)
ngrad = min(100, 2 * n, n + 10)
# Utility functions
is.nainf <- function(x) any(is.na(x) | is.infinite(x))
# Initializations, all vectors should be column vectors
x <- x0
H <- H0
f <- fn(x)
g <- as.matrix(gr(x))
d <- g
G <- g
X <- x
nG <- 1
w <- 1
dnorm <- norm(g, type = "f")
# Checking error and end conditions
if (is.nainf(f) || is.nainf(g)) {
errno <- 5
mess <- "Function or its gradient not defined at initial iterate."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X, G = G,
w = w))
}
if (f < fvalquit) {
errno <- 2
mess <- "Function value found below target at initial iterate."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X, G = G,
w = w))
}
if (dnorm < normtol) {
errno <- 0
mess <- "Tolerance o gradient satisfied at initial iterate."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X, G = G,
w = w))
}
if (norm(x, "f") > xnormquit) {
errno <- 3
mess <- "Value of norm(x) exceeds limit at initial iterate."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X, G = G,
w = w))
}
# -- Begin main loop ----------------
for (iter in 1:maxit) {
# -- Full BFGS, no limited memory version
p <- -H %*% g
gtp <- c(t(g) %*% p)
if (gtp >= 0 || is.na(gtp)) {
errno <- 6
mess <- "Found non-descent direction only, will quit."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X,
G = G, w = w))
}
gprev <- g # for BFGS update
if (strongwolfe) {
sls <- linesch_sw(fn, gr, x, d = p, f0 = fn(x), grad0 = gr(x), c1 = wolfe1, c2 = wolfe2, fvalquit,
prtlevel)
alpha <- sls$alpha
x <- sls$x
f <- sls$f
g <- sls$grd
fail <- sls$fail
} else {
wls <- linesch_ww(fn, gr, x, d = p, fn0 = fn(x), gr0 = gr(x), c1 = wolfe1, c2 = wolfe2)
alpha <- wls$alpha
x <- as.matrix(wls$xalpha)
f <- wls$falpha
g <- as.matrix(wls$galpha)
fail <- wls$fail
}
# discard the saved gradients iff the new point x is not sufficiently close to the previous point and
# replace them by new gradient
if (alpha * norm(p, "f") > evaldist) {
nG <- 1
G <- g
X <- x
# otherwise add new gradient to set of saved gradients, discarding oldest if already have ngrad saved
# gradients
} else if (nG < ngrad) {
nG <- nG + 1
G <- cbind(g, G)
X <- cbind(x, X)
} else {
# nG = ngrad
G <- cbind(g, G[, 1:(ngrad - 1)])
X <- cbind(x, X[, 1:(ngrad - 1)])
}
# compute smallest vector in convex hull of qualifying gradients: reduces to norm of latest gradient if
# ngrad == 1, and the set must always have at least one gradient: could gain efficiency here by updating
# previous QP solution
if (nG > 1) {
qps <- qpspecial(as.matrix(G))
w <- qps$x
d <- qps$d
} else {
w <- 1
d <- g
}
dnorm <- sqrt(sum(d * d))
if (f < fvalquit) {
errno <- 2
mess <- "Reached target objective, quit during iteration."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X,
G = G, w = w))
} else if (norm(x) > xnormquit) {
errno <- 3
mess <- "The value of norm(x) exceeds limit during iteration."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X,
G = G, w = w))
}
# Line search failed (Wolfe conditions not both satisfied)
if (fail == 1) {
if (!quitLSfail) {
warning("BFGS: Search continued although line search failed.")
} else {
errno <- 7
mess <- "Quit at as line search failed during iteration."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess,
X = X, G = G, w = w))
}
# Function apparently unbounded from below
} else if (fail == -1) {
errno <- 8
mess <- "Quit as f may be unbounded from below."
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X,
G = G, w = w))
}
if (dnorm <= normtol) {
if (nG == 1) {
mess <- "Gradient norm below tolerance, quit iteration."
} else {
mess <- "Norm of smallest vector below tolerance, quit."
}
errno <- 0
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X,
G = G, w = w))
}
# Continue with iteration
s <- alpha * p
y <- g - gprev
sty <- c(t(s) %*% y)
# Perform rank two BFGS update to the inverse Hessian H
if (sty > 0) {
if (iter == 1 && scale) {
H <- c(sty/(t(y) %*% y)) * H
}
rho <- 1/sty
# rhoHyst <- rho * (H %*% y) %*% t(s) H <- H - t(rhoHyst) - rhoHyst + rho * s %*% (t(y) %*% rhoHyst) +
# rho * s %*% t(s) ## this was in old version new update for symmetry
Hy <- H %*% y
rhoHyst <- (rho * Hy) %*% t(s)
ytHy <- t(y) %*% Hy
sstfactor <- max(rho * rho * ytHy, 0)
sscaled <- sqrt(sstfactor) * s
H <- H - (t(rhoHyst) + rhoHyst) + sscaled %*% t(sscaled)
} else {
if (prtlevel > 0)
cat("BFGS: sty<=0 during iteration, skipping bfgs update.\n")
}
} # end for
mess <- "Maximum number of iterations reached; may not converge."
errno <- 1
return(list(x = c(x), f = f, d = c(d), H = H, iter = iter, info = errno, message = mess, X = X, G = G,
w = w))
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.