Squared Extrapolation Methods for Accelerating Slowly-Convergent Fixed-Point Iterations
squarem.RdGlobally-convergent, partially monotone, acceleration schemes for accelerating the convergence of *any* smooth, monotone, slowly-converging contraction mapping. It can be used to accelerate the convergence of a wide variety of iterations including the expectation-maximization (EM) algorithms and its variants, majorization-minimization (MM) algorithm, power method for dominant eigenvalue-eigenvector, Google's page-rank algorithm, and multi-dimensional scaling.
Usage
squarem(par, fixptfn, objfn, ... , control=list())Arguments
- par
A vector of parameters denoting the initial guess for the fixed-point.
- fixptfn
A vector function, $F$ that denotes the fixed-point mapping. This function is the most essential input in the package. It should accept a parameter vector as input and should return a parameter vector of same length. This function defines the fixed-point iteration: \(x_{k+1} = F(x_k)\). In the case of EM algorithm, \(F\) defines a single E and M step.
- objfn
This is a scalar function, \(L\), that denotes a ”merit” function which attains its local maximum or minimum at the fixed -point of \(F\). Also see the control parameter
minimizewhich determines whether the objective function is minimized or maximized. The objective function should accept a parameter vector as input and should return a scalar value. In the EM algorithm, the merit function \(L\) is the either log-likelihood or its negative. In someproblems, a natural merit function may not exist, in which case the algorithm works with onlyfixptfn. The merit function functionobjfndoes not have to be specified, even when a natural merit function is available, especially when its computation is expensive.- control
A list of control parameters specifing any changes to default values of algorithm control parameters. Full names of control list elements must be specified, otherwise, user-specifications are ignored. See *Details*.
- ...
Arguments passed to
fixptfnandobjfn.
Value
A list with the following components:
- par
Parameter, \(x*\) that are the fixed-point of \(F\) such that \(x* = F(x*)\), if convergence is successful.
- value.objfn
The value of the objective function $L$ at termination.
- fpevals
Number of times the fixed-point function
fixptfnwas evaluated.- objfevals
Number of times the objective function
objfnwas evaluated.- convergence
An integer code indicating type of convergence.
0indicates successful convergence, whereas1denotes failure to converge.- p.intermed
A matrix where each row corresponds to parameters at each iteration, along with the corresponding log-likelihood value. This object is returned only when the control parameter
intermedis set toTRUE. It is not returned whenobjfnis not specified.
Details
The function squarem is a general-purpose algorithm for accelerating
the convergence of any slowly-convergent (smooth) fixed-point iteration.
Full names of control parameters must be specified; otherwise, user specifications
are ignored.
Default values of control are:
K = 1, method = 3, minimize = TRUE, square = TRUE,
step.min0 = 1, step.max0 = 1, mstep = 4,
objfn.inc = 1, kr = 1, tol = 1e-07,
maxiter = 1500, trace = FALSE, intermed = FALSE.
KAn integer denoting the order of the SQUAREM scheme. Default is 1, which is a first-order scheme developed in Varadhan and Roland (2008). First-order schemes are adequate for most problems.
K = 2, 3may provide greater speed in some problems, although they are less reliable than first-order schemes.methodEither an integer or a character variable that denotes the particular SQUAREM scheme to be used. When
K = 1, method should be an integer: 1, 2, or 3. These correspond to the 3 schemes discussed in Varadhan and Roland (2008). Default ismethod = 3. WhenK > 1, method should be a character string, either"RRE"or"MPE". These correspond to reduced-rank extrapolation or squared minimal polynomial extrapolation (see Roland, Varadhan, and Frangakis (2007)). Default is"RRE".minimizeA logical variable. By default it is set to
TRUEfor minimization of the objective function. If the objective function is to be maximized (commonly the case for likelihood estimation), set toFALSE.squareA logical variable indicating whether a squared extrapolation scheme should be used. Squared extrapolation schemes are typically faster and more stable than unsquared schemes. Default is
TRUE.step.min0A scalar denoting the minimum steplength taken by a SQUAREM algorithm. Default is 1. For contractive fixed-point iterations (e.g., EM and MM), this default works well. In problems where an eigenvalue of the Jacobian of \(F\) is outside of the interval \((0,1)\),
step.min0should be less than 1 or even negative in some cases.step.max0A positive-valued scalar denoting the initial value of the maximum steplength taken by a SQUAREM algorithm. Default is 1. When the steplength computed by SQUAREM exceeds
step.max0, the steplength is set equal tostep.max0, but thenstep.max0is increased by a factor ofmstep.mstepA scalar greater than 1. When the steplength computed by SQUAREM exceeds
step.max0, the steplength is set equal tostep.max0, butstep.max0is increased by a factor ofmstep. Default is 4.objfn.incA non-negative scalar that dictates the degree of non-monotonicity. Default is 1. Set
objfn.inc = 0to obtain monotone convergence. Settingobjfn.inc = Infgives a non-monotone scheme. In-between values result in partially-monotone convergence.krA non-negative scalar that dictates the degree of non-monotonicity. Default is 1. Set
kr = 0to obtain monotone convergence. Settingkr = Infgives a non-monotone scheme. In-between values result in partially-monotone convergence. This parameter is only used whenobjfnis not specified by the user.tolA small, positive scalar that determines when iterations should be terminated. Iteration stops when \(||x_k - F(x_k)|| \leq tol\). Default is
1e-07.maxiterAn integer denoting the maximum limit on the number of evaluations of
fixptfn, \(F\). Default is 1500.traceA logical variable denoting whether intermediate results of iterations should be displayed. Default is
FALSE.intermedA logical variable denoting whether intermediate results of iterations should be returned. If set to
TRUE, the function will return a matrix where each row corresponds to parameters at each iteration, along with the corresponding log-likelihood value. Whenobjfnis not specified, it will return the fixed-point residual instead of the objective function values. Default isFALSE.
References
R Varadhan and C Roland (2008), Simple and globally convergent numerical schemes for accelerating the convergence of any EM algorithm, Scandinavian Journal of Statistics, 35:335-353.
C Roland, R Varadhan, and CE Frangakis (2007), Squared polynomial extrapolation methods with cycling: an application to the positron emission tomography problem, Numerical Algorithms, 44:159-172.
Y Du and R Varadhan (2020), SQUAREM: An R package for off-the-shelf acceleration of EM, MM, and other EM-like monotone algorithms, Journal of Statistical Software, 92(7): 1-41. <doi:10.18637/jss.v092.i07>
Examples
###########################################################################
# Also see the vignette by typing:
# vignette("SQUAREM", all=FALSE)
#
# Example 1: EM algorithm for Poisson mixture estimation
poissmix.em <- function(p,y) {
# The fixed point mapping giving a single E and M step of the EM algorithm
#
pnew <- rep(NA,3)
i <- 0:(length(y)-1)
zi <- p[1]*exp(-p[2])*p[2]^i / (p[1]*exp(-p[2])*p[2]^i + (1 - p[1])*exp(-p[3])*p[3]^i)
pnew[1] <- sum(y*zi)/sum(y)
pnew[2] <- sum(y*i*zi)/sum(y*zi)
pnew[3] <- sum(y*i*(1-zi))/sum(y*(1-zi))
p <- pnew
return(pnew)
}
poissmix.loglik <- function(p,y) {
# Objective function whose local minimum is a fixed point
# negative log-likelihood of binary poisson mixture
i <- 0:(length(y)-1)
loglik <- y*log(p[1]*exp(-p[2])*p[2]^i/exp(lgamma(i+1)) +
(1 - p[1])*exp(-p[3])*p[3]^i/exp(lgamma(i+1)))
return ( -sum(loglik) )
}
# Real data from Hasselblad (JASA 1969)
poissmix.dat <- data.frame(death=0:9, freq=c(162,267,271,185,111,61,27,8,3,1))
y <- poissmix.dat$freq
tol <- 1.e-08
# Use a preset seed so the example is reproducable.
require("setRNG")
old.seed <- setRNG(list(kind="Mersenne-Twister", normal.kind="Inversion",
seed=54321))
p0 <- c(runif(1),runif(2,0,4)) # random starting value
# Basic EM algorithm
pf1 <- fpiter(p=p0, y=y, fixptfn=poissmix.em, objfn=poissmix.loglik, control=list(tol=tol))
# First-order SQUAREM algorithm with SqS3 method
pf2 <- squarem(par=p0, y=y, fixptfn=poissmix.em, objfn=poissmix.loglik,
control=list(tol=tol))
# First-order SQUAREM algorithm with SqS2 method
pf3 <- squarem(par=p0, y=y, fixptfn=poissmix.em, objfn=poissmix.loglik,
control=list(method=2, tol=tol))
# First-order SQUAREM algorithm with SqS3 method; non-monotone
# Note: the objective function is not evaluated when objfn.inc = Inf
pf4 <- squarem(par=p0,y=y, fixptfn=poissmix.em,
control=list(tol=tol, objfn.inc=Inf))
# First-order SQUAREM algorithm with SqS3 method;
# objective function is not specified
pf5 <- squarem(par=p0,y=y, fixptfn=poissmix.em, control=list(tol=tol, kr=0.1))
# Second-order (K=2) SQUAREM algorithm with SqRRE
pf6 <- squarem(par=p0, y=y, fixptfn=poissmix.em, objfn=poissmix.loglik,
control=list (K=2, tol=tol))
# Second-order SQUAREM algorithm with SqRRE; objective function is not specified
pf7 <- squarem(par=p0, y=y, fixptfn=poissmix.em, control=list(K=2, tol=tol))
# Comparison of converged parameter estimates
par.mat <- rbind(pf1$par, pf2$par, pf3$par, pf4$par, pf5$par, pf6$par, pf7$par)
par.mat
#> [,1] [,2] [,3]
#> [1,] 0.6401136 2.663406 1.256097
#> [2,] 0.6401146 2.663404 1.256095
#> [3,] 0.6401142 2.663405 1.256096
#> [4,] 0.6401146 2.663404 1.256095
#> [5,] 0.6401146 2.663404 1.256095
#> [6,] 0.6401146 2.663404 1.256095
#> [7,] 0.6401146 2.663404 1.256095
# Compare objective function values
# (note: `NA's indicate that \code{objfn} was not specified)
c(pf1$value, pf2$value, pf3$value, pf4$value,
pf5$value, pf6$value, pf7$value)
#> [1] 1989.946 1989.946 1989.946 NA NA 1989.946 NA
# Compare number of fixed-point evaluations
c(pf1$fpeval, pf2$fpeval, pf3$fpeval, pf4$fpeval,
pf5$fpeval, pf6$fpeval, pf7$fpeval)
#> [1] 2426 45 36 45 45 26 26
# Compare mumber of objective function evaluations
# (note: `0' indicate that \code{objfn} was not specified)
c(pf1$objfeval, pf2$objfeval, pf3$objfeval, pf4$objfeval,
pf5$objfeval, pf6$objfeval, pf7$objfeval)
#> [1] 0 16 13 0 0 6 0
###############################################################
# Example 2: Same as above (i.e. Poisson mixture)
# but now showing how to "maximize" the log-likelihood
poissmix.loglik.max <- function(p,y) {
# Objective function which is to be *maximized*
# Log-likelihood of binary poisson mixture
i <- 0:(length(y)-1)
loglik <- y*log(p[1]*exp(-p[2])*p[2]^i/exp(lgamma(i+1)) +
(1 - p[1])*exp(-p[3])*p[3]^i/exp(lgamma(i+1)))
return ( sum(loglik) )
}
# Maximizing the log-likelihood
# Note: the control parameter `minimize' is set to FALSE
#
pf.max <- squarem(par=p0, y=y, fixptfn=poissmix.em, objfn=poissmix.loglik.max,
control=list(tol=tol, minimize=FALSE))
pf.max
#> $par
#> [1] 0.6401146 2.6634044 1.2560951
#>
#> $value.objfn
#> [1] -1989.946
#>
#> $iter
#> [1] 16
#>
#> $fpevals
#> [1] 45
#>
#> $objfevals
#> [1] 16
#>
#> $convergence
#> [1] TRUE
#>
##############################################################################
# Example 3: Accelerating the convergence of power method iteration
# for finding the dominant eigenvector of a matrix
power.method <- function(x, A) {
# Defines one iteration of the power method
# x = starting guess for dominant eigenvector
# A = a square matrix
ax <- as.numeric(A %*% x)
f <- ax / sqrt(as.numeric(crossprod(ax)))
f
}
# Finding the dominant eigenvector of the Bodewig matrix
b <- c(2, 1, 3, 4, 1, -3, 1, 5, 3, 1, 6, -2, 4, 5, -2, -1)
bodewig.mat <- matrix(b,4,4)
eigen(bodewig.mat)
#> eigen() decomposition
#> $values
#> [1] 7.932905 5.668864 -1.573191 -8.028578
#>
#> $vectors
#> [,1] [,2] [,3] [,4]
#> [1,] -0.5601445 0.3787027 0.6880479 0.2634624
#> [2,] -0.2116328 0.3624190 -0.6241229 0.6590407
#> [3,] -0.7767083 -0.5379352 -0.2598009 -0.1996335
#> [4,] -0.1953816 0.6601988 -0.2637503 -0.6755734
#>
p0 <- rnorm(4)
# Standard power method iteration
ans1 <- fpiter(p0, fixptfn=power.method, A=bodewig.mat)
# re-scaling the eigenvector so that it has unit length
ans1$par <- ans1$par / sqrt(sum(ans1$par^2))
ans1
#> $par
#> [1] -0.2634624 -0.6590407 0.1996335 0.6755734
#>
#> $value.objfn
#> [1] NA
#>
#> $fpevals
#> [1] 5000
#>
#> $objfevals
#> [1] 0
#>
#> $convergence
#> [1] FALSE
#>
# First-order SQUAREM with default settings
ans2 <- squarem(p0, fixptfn=power.method, A=bodewig.mat, control=list(K=1))
ans2$par <- ans2$par / sqrt(sum(ans2$par^2))
ans2
#> $par
#> [1] 0.2634624 0.6590407 -0.1996335 -0.6755734
#>
#> $value.objfn
#> [1] NA
#>
#> $iter
#> [1] 751
#>
#> $fpevals
#> [1] 1500
#>
#> $objfevals
#> [1] 0
#>
#> $convergence
#> [1] FALSE
#>
# First-order SQUAREM with a smaller step.min0
# Convergence is dramatically faster now!
ans3 <- squarem(p0, fixptfn=power.method, A=bodewig.mat, control=list(step.min0 = 0.5))
ans3$par <- ans3$par / sqrt(sum(ans3$par^2))
ans3
#> $par
#> [1] -0.5601445 -0.2116328 -0.7767082 -0.1953817
#>
#> $value.objfn
#> [1] NA
#>
#> $iter
#> [1] 9
#>
#> $fpevals
#> [1] 24
#>
#> $objfevals
#> [1] 0
#>
#> $convergence
#> [1] TRUE
#>
# Second-order SQUAREM
ans4 <- squarem(p0, fixptfn=power.method, A=bodewig.mat, control=list(K=2, method="rre"))
ans4$par <- ans4$par / sqrt(sum(ans4$par^2))
ans4
#> $par
#> [1] -0.5601445 -0.2116328 -0.7767083 -0.1953816
#>
#> $value.objfn
#> [1] NA
#>
#> $iter
#> [1] 7
#>
#> $fpevals
#> [1] 31
#>
#> $objfevals
#> [1] 0
#>
#> $convergence
#> [1] TRUE
#>