Nothing
#' @importFrom methods is
# Manually translated from a publicly available Matlab code:
# https://au.mathworks.com/matlabcentral/fileexchange/27183-lsmr--an-iterative-algorithm-for-least-squares-problems
lsmr <- function(A,
b,
lambda = 0,
atol = 1e-6,
btol = 1e-6,
conlim = 1e+8,
itnlim = NULL,
localSize = 0,
show = FALSE) {
# LSMR Iterative solver for least-squares problems.
# X = LSMR(A,B) solves the system of linear equations A*X=B. If the system
# is inconsistent, it solves the least-squares problem min ||b - Ax||_2.
# A is a rectangular matrix of dimension m-by-n, where all cases are
# allowed: m=n, m>n, or m<n. B is a vector of length m.
# The matrix A may be dense or sparse (usually sparse).
# X = LSMR(AFUN,B) takes a function handle AFUN instead of the matrix A.
# AFUN(X,1) takes a vector X and returns A*X. AFUN(X,2) returns A'*X.
# AFUN can be used in all the following syntaxes.
# X = LSMR(A,B,LAMBDA) solves the regularized least-squares problem
# min ||(B) - ( A )X||
# ||(0) (LAMBDA*I) ||_2
# where LAMBDA is a scalar. If LAMBDA is [] or 0, the system is solved
# without regularization.
# X = LSMR(A,B,LAMBDA,ATOL,BTOL) continues iterations until a certain
# backward error estimate is smaller than some quantity depending on
# ATOL and BTOL. Let RES = B - A*X be the residual vector for the
# current approximate solution X. If A*X = B seems to be consistent,
# LSMR terminates when NORM(RES) <= ATOL*NORM(A)*NORM(X) + BTOL*NORM(B).
# Otherwise, LSMR terminates when NORM(A'*RES) <= ATOL*NORM(A)*NORM(RES).
# If both tolerances are 1.0e-6 (say), the final NORM(RES) should be
# accurate to about 6 digits. (The final X will usually have fewer
# correct digits, depending on cond(A) and the size of LAMBDA.)
# If ATOL or BTOL is [], a default value of 1.0e-6 will be used.
# Ideally, they should be estimates of the relative error in the
# entries of A and B respectively. For example, if the entries of A
# have 7 correct digits, set ATOL = 1e-7. This prevents the algorithm
# from doing unnecessary work beyond the uncertainty of the input data.
# X = LSMR(A,B,LAMBDA,ATOL,BTOL,CONLIM) terminates if an estimate
# of cond(A) exceeds CONLIM. For compatible systems Ax = b,
# conlim could be as large as 1.0e+12 (say). For least-squares problems,
# conlim should be less than 1.0e+8. If CONLIM is [], the default value
# is CONLIM = 1e+8. Maximum precision can be obtained by setting
# ATOL = BTOL = CONLIM = 0, but the number of iterations may then be
# excessive.
# X = LSMR(A,B,LAMBDA,ATOL,BTOL,CONLIM,ITNLIM) terminates if the
# number of iterations reaches ITNLIM. The default is ITNLIM = min(m,n).
# For ill-conditioned systems, a larger value of ITNLIM may be needed.
# X = LSMR(A,B,LAMBDA,ATOL,BTOL,CONLIM,ITNLIM,LOCALSIZE) runs LSMR
# with reorthogonalization on the last LOCALSIZE v_k's (v-vectors
# generated by the Golub-Kahan bidiagonalization). LOCALSIZE = 0 or []
# runs LSMR without reorthogonalization. LOCALSIZE = Inf specifies
# full reorthogonalization of the v_k's. Reorthogonalizing only u_k or
# both u_k and v_k are not an option here, because reorthogonalizing all
# v_k's makes the u_k's close to orthogonal. Details are given in the
# submitted SIAM paper.
# X = LSMR(A,B,LAMBDA,ATOL,BTOL,CONLIM,ITNLIM,LOCALSIZE,SHOW) prints an
# iteration log if SHOW=TRUE. The default value is SHOW=FALSE.
# [X,ISTOP] = LSMR(A,B,...) gives the reason for termination.
# ISTOP = 0 means X=0 is a solution.
# = 1 means X is an approximate solution to A*X = B,
# according to ATOL and BTOL.
# = 2 means X approximately solves the least-squares problem
# according to ATOL.
# = 3 means COND(A) seems to be greater than CONLIM.
# = 4 is the same as 1 with ATOL = BTOL = EPS.
# = 5 is the same as 2 with ATOL = EPS.
# = 6 is the same as 3 with CONLIM = 1/EPS.
# = 7 means ITN reached ITNLIM before the other stopping
# conditions were satisfied.
# [X,ISTOP,ITN] = LSMR(A,B,...) gives ITN = the number of LSMR iterations.
# [X,ISTOP,ITN,NORMR] = LSMR(A,B,...) gives an estimate of the residual
# norm: NORMR = norm(B-A*X).
# [X,ISTOP,ITN,NORMR,NORMAR] = LSMR(A,B,...) gives an estimate of the
# residual for the normal equation: NORMAR = NORM(A'*(B-A*X)).
# [X,ISTOP,ITN,NORMR,NORMAR,NORMA] = LSMR(A,B,...) gives an estimate of
# the Frobenius norm of A.
# [X,ISTOP,ITN,NORMR,NORMAR,NORMA,CONDA] = LSMR(A,B,...) gives an estimate
# of the condition number of A.
# [X,ISTOP,ITN,NORMR,NORMAR,NORMA,CONDA,NORMX] = LSMR(A,B,...) gives an
# estimate of NORM(X).
# LSMR uses an iterative method requiring matrix-vector products A*v
# and A'*u. For further information, see
# D. C.-L. Fong and M. A. Saunders,
# LSMR: An iterative algorithm for sparse least-squares problems,
# SIAM J. Sci. Comput., submitted 1 June 2010.
# See http://www.stanford.edu/~clfong/lsmr.html.
# 08 Dec 2009: First release version of LSMR.
# 09 Apr 2010: Updated documentation and default parameters.
# 14 Apr 2010: Updated documentation.
# 03 Jun 2010: LSMR with local and/or full reorthogonalization of v_k.
# 10 Mar 2011: Bug fix in reorthgonalization. (suggested by David Gleich)
# David Chin-lung Fong clfong@stanford.edu
# Institute for Computational and Mathematical Engineering
# Stanford University
# Michael Saunders saunders@stanford.edu
# Systems Optimization Laboratory
# Dept of MS&E, Stanford University.
#-----------------------------------------------------------------------
#---------------------------------------------------------------------
# Nested functions.
#---------------------------------------------------------------------
localVEnqueue <- function(v) {
# Store v into the circular buffer localV.
if (localPointer < localSize) {
localPointer <- localPointer + 1
} else {
localPointer <- 1
localVQueueFull <- TRUE
}
localV[, localPointer] <- v
} # nested function localVEnqueue
#---------------------------------------------------------------------
localVOrtho <- function(v) {
# Perform local reorthogonalization of V.
vOutput <- v
if (localVQueueFull) {
localOrthoLimit <- localSize
} else {
localOrthoLimit <- localPointer
}
for (localOrthoCount in 1:localOrthoLimit) {
vtemp <- localV[, localOrthoCount]
vOutput <- vOutput - (t(vOutput) %*% vtemp) * vtemp
}
return(vOutput)
} # nested function localVOrtho
# Initialize.
if (!is.null(dim(A))) {
explicitA <- TRUE
} else {
if (is(A, "function")) {
explicitA <- FALSE
} else {
stop("A must be numeber or a function")
}
}
msg <- c(
"The exact solution is x = 0 ",
"Ax - b is small enough, given atol, btol ",
"The least-squares solution is good enough, given atol ",
"The estimate of cond(Abar) has exceeded conlim ",
"Ax - b is small enough for this machine ",
"The least-squares solution is good enough for this machine",
"Cond(Abar) seems to be too large for this machine ",
"The iteration limit has been reached "
)
hdg1 <- " itn x(1) norm r norm A'r"
hdg2 <- " compatible LS norm A cond A"
pfreq <- 20 # print frequency (for repeating the heading)
pcount <- 0 # print counter
# Determine dimensions m and n, and
# form the first vectors u and v.
# These satisfy beta*u = b, alpha*v = A'u.
u <- b
beta <- sqrt(sum(u^2))
if (beta > 0) {
u <- u / beta
}
if (explicitA) {
v <- t(A) %*% u
m <- dim(A)[1]
n <- dim(A)[2]
} else {
v <- A(u, 2)
m <- length(b)
n <- length(v)
}
minDim <- min(m, n)
if (is.null(itnlim)) itnlim <- minDim
if (show) {
cat("\n\nLSMR Least-squares solution of Ax = b")
cat("\nVersion 1.11 09 Jun 2010")
cat(sprintf("\nThe matrix A has %8g rows and %8g cols", m, n))
cat(sprintf("\nlambda = %16.10e", lambda))
cat(sprintf("\natol = %8.2e conlim = %8.2e", atol, conlim))
cat(sprintf("\nbtol = %8.2e itnlim = %8g", btol, itnlim))
}
alpha <- sqrt(sum(v^2))
if (alpha > 0) {
v <- (1 / alpha) * v
}
# Initialization for local reorthogonalization.
localOrtho <- FALSE
if (localSize > 0) {
localPointer <- 0
localOrtho <- TRUE
localVQueueFull <- FALSE
# Preallocate storage for the relevant number of latest v_k's.
localV <- matrix(0, n, min(localSize, minDim))
}
# Initialize variables for 1st iteration.
itn <- 0
zetabar <- alpha * beta
alphabar <- alpha
rho <- 1
rhobar <- 1
cbar <- 1
sbar <- 0
h <- v
hbar <- matrix(0, n, 1)
x <- matrix(0, n, 1)
# Initialize variables for estimation of ||r||.
betadd <- beta
betad <- 0
rhodold <- 1
tautildeold <- 0
thetatilde <- 0
zeta <- 0
d <- 0
# Initialize variables for estimation of ||A|| and cond(A).
normA2 <- alpha^2
maxrbar <- 0
minrbar <- 1e+100
# Items for use in stopping rules.
normb <- beta
istop <- 0
ctol <- 0
if (conlim > 0) ctol <- 1 / conlim
normr <- beta
# Exit if b=0 or A'b = 0.
normAr <- alpha * beta
if (normAr == 0) {
stop(msg[1])
}
# Heading for iteration log.
if (show) {
test1 <- 1
test2 <- alpha / beta
cat(sprintf("\n\n%s%s", hdg1, hdg2))
cat(sprintf("\n%6g %12.5e", itn, x(1)))
cat(sprintf(" %10.3e %10.3e", normr, normAr))
cat(sprintf(" %8.1e %8.1e", test1, test2))
}
#------------------------------------------------------------------
# Main iteration loop.
#------------------------------------------------------------------
while (itn < itnlim) {
itn <- itn + 1
# Perform the next step of the bidiagonalization to obtain the
# next beta, u, alpha, v. These satisfy the relations
# beta*u = A*v - alpha*u,
# alpha*v = A'*u - beta*v.
if (explicitA) {
u <- A %*% v - alpha * u
} else {
u <- A(v, 1) - alpha * u
}
beta <- sqrt(sum(u^2))
if (beta > 0) {
u <- (1 / beta) * u
if (localOrtho) {
localVEnqueue(v) # Store old v for local reorthogonalization of new v.
}
if (explicitA) {
v <- t(A) %*% u - beta * v
} else {
v <- A(u, 2) - beta * v
}
if (localOrtho) {
v <- localVOrtho(v) # Local-reorthogonalization of new v.
}
alpha <- sqrt(sum(v^2))
if (alpha > 0) {
v <- (1 / alpha) * v
}
}
# At this point, beta = beta_{k+1}, alpha = alpha_{k+1}.
# Construct rotation Qhat_{k,2k+1}.
alphahat <- sqrt(sum(c(alphabar, lambda)^2))
chat <- alphabar / alphahat
shat <- lambda / alphahat
# Use a plane rotation (Q_i) to turn B_i to R_i.
rhoold <- rho
rho <- sqrt(sum(c(alphahat, beta)^2))
c <- alphahat / rho
s <- beta / rho
thetanew <- s * alpha
alphabar <- c * alpha
# Use a plane rotation (Qbar_i) to turn R_i^T to R_i^bar.
rhobarold <- rhobar
zetaold <- zeta
thetabar <- sbar * rho
rhotemp <- cbar * rho
rhobar <- sqrt(sum(c(cbar * rho, thetanew)^2))
cbar <- cbar * rho / rhobar
sbar <- thetanew / rhobar
zeta <- cbar * zetabar
zetabar <- -sbar * zetabar
# Update h, h_hat, x.
hbar <- h - (thetabar * rho / (rhoold * rhobarold)) * hbar
x <- x + (zeta / (rho * rhobar)) * hbar
h <- v - (thetanew / rho) * h
# Estimate of ||r||.
# Apply rotation Qhat_{k,2k+1}.
betaacute <- chat * betadd
betacheck <- -shat * betadd
# Apply rotation Q_{k,k+1}.
betahat <- c * betaacute
betadd <- -s * betaacute
# Apply rotation Qtilde_{k-1}.
# betad = betad_{k-1} here.
thetatildeold <- thetatilde
rhotildeold <- sqrt(sum(c(rhodold, thetabar)^2))
ctildeold <- rhodold / rhotildeold
stildeold <- thetabar / rhotildeold
thetatilde <- stildeold * rhobar
rhodold <- ctildeold * rhobar
betad <- -stildeold * betad + ctildeold * betahat
# betad = betad_k here.
# rhodold = rhod_k here.
tautildeold <- (zetaold - thetatildeold * tautildeold) / rhotildeold
taud <- (zeta - thetatilde * tautildeold) / rhodold
d <- d + betacheck^2
normr <- sqrt(d + (betad - taud)^2 + betadd^2)
# Estimate ||A||.
normA2 <- normA2 + beta^2
normA <- sqrt(normA2)
normA2 <- normA2 + alpha^2
# Estimate cond(A).
maxrbar <- max(maxrbar, rhobarold)
if (itn > 1) {
minrbar <- min(minrbar, rhobarold)
}
condA <- max(maxrbar, rhotemp) / min(minrbar, rhotemp)
# Test for convergence.
# Compute norms for convergence testing.
normAr <- abs(zetabar)
normx <- sqrt(sum(x^2))
# Now use these norms to estimate certain other quantities,
# some of which will be small near a solution.
test1 <- normr / normb
test2 <- normAr / (normA * normr)
test3 <- 1 / condA
t1 <- test1 / (1 + normA * normx / normb)
rtol <- btol + atol * normA * normx / normb
# The following tests guard against extremely small values of
# atol, btol or ctol. (The user may have set any or all of
# the parameters atol, btol, conlim to 0.)
# The effect is equivalent to the normAl tests using
# atol = eps, btol = eps, conlim = 1/eps.
if (itn >= itnlim) istop <- 7
if (1 + test3 <= 1) istop <- 6
if (1 + test2 <= 1) istop <- 5
if (1 + t1 <= 1) istop <- 4
# Allow for tolerances set by the user.
if (test3 <= ctol) istop <- 3
if (test2 <= atol) istop <- 2
if (test1 <= rtol) istop <- 1
# See if it is time to print something.
if (show) {
prnt <- 0
if (n <= 40) prnt <- 1
if (itn <= 10) prnt <- 1
if (itn >= itnlim - 10) prnt <- 1
if (itn %% 10 == 0) prnt <- 1
if (test3 <= 1.1 * ctol) prnt <- 1
if (test2 <= 1.1 * atol) prnt <- 1
if (test1 <= 1.1 * rtol) prnt <- 1
if (istop != 0) prnt <- 1
if (prnt) {
if (pcount >= pfreq) {
pcount <- 0
cat(sprintf("\n\n%s%s", hdg1, hdg2))
}
pcount <- pcount + 1
cat(sprintf("\n%6g %12.5e", itn, x(1)))
cat(sprintf(" %10.3e %10.3e", normr, normAr))
cat(sprintf(" %8.1e %8.1e", test1, test2))
cat(sprintf(" %8.1e %8.1e", normA, condA))
}
}
if (istop > 0) {
break
}
} # iteration loop
# Print the stopping condition.
if (show) {
cat(sprintf("\n\nLSMR finished"))
cat(sprintf("\n%s", msg[istop + 1]))
cat(sprintf("\nistop =%8g normr =%8.1e", istop, normr))
cat(sprintf(" normA =%8.1e normAr =%8.1e", normA, normAr))
cat(sprintf("\nitn =%8g condA =%8.1e", itn, condA))
cat(sprintf(" normx =%8.1e\n", normx))
}
return(list(
x = x,
istop = istop,
itn = itn,
normr = normr,
normAr = normAr,
normA = normA,
condA = condA,
normx = normx
))
}
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.