Hi,

Here is one approach to solve your likelihood maximization subject to 
constraints.  I have written a function called `constrOptim.nl' that can solve 
constrained optimization problems.  I will demonstrate this with a simulation.

# 1.  Simulate the data (x,y).

a <- 4
b <- 1
c <- 2.5
p <- 0.3
n <- 100
z <- rbinom(n, size=1, prob=p)
x <- ifelse(z, rpois(n, a), rpois(n, a+c))
y <- ifelse(z, rpois(n, b+c), rpois(n, b))

# 2.  Define the log-likelihood to be maximized

mloglik <- function(par, xx, y, ...){
# Note that I have named `xx' instead of `x' to avoid conflict with another 
function 
p <- par[1]
a <- par[2]
b <- par[3]
cc <- par[4]
sum(log(p*dpois(xx,a)*dpois(y,b+cc) + (1-p)*dpois(xx,a+cc)*dpois(y,b)))
}

# 3. Write the constraint function to define inequalities

hin <- function(par, ...) {
# All constraints are defined such that h[i] > 0 for all i.
h <- rep(NA, 7)
h[1] <- par[1]
h[2] <- 1 - par[1] 
h[3] <- par[2]
h[4] <- par[3]
h[5] <- par[4]
h[6] <- par[2] - par[4]
h[7] <- par[3] - par[4]
h
}

# Now, we are almost ready to maximize the log-likelihood.  We need a feasible 
starting value.  
# We construct a projection function that can convert any arbitrary real vector 
to a feasible starting vector.

# 5.  Finding a feasible starting vector of parameter values

project <- function(par, lower, upper) {
# a function to map a random vector to a feasible vector
slack <- 1.e-14
if (par[1] <= 0) par[1] <- slack
if (par[1] >= 1) par[1] <- 1 - slack
if (par[2] <= 0) par[2] <- slack
if (par[3] <= 0) par[3] <- slack
par[4] <- min(par[2], par[3], par[4]) - slack
par
} 

p0c <- runif(4, c(0,1,1,1), c(1, 5, 5, 2))  # a random candidate starting value
p0 <- project(p0c)  # feasible starting value

# 6.  Optimization

source("constrOptim_nl.R")  # we source the `constrOptim.nl' function
ans <- constrOptim.nl(par=p0, fn=mloglik, hin=hin, xx=x, y=y, 
control=list(fnscale=-1)) # Note: we are maximizing
ans


This concludes our brief tutorial.   

Hope this helps,
Ravi.

____________________________________________________________________

Ravi Varadhan, Ph.D.
Assistant Professor,
Division of Geriatric Medicine and Gerontology
School of Medicine
Johns Hopkins University

Ph. (410) 502-2619
email: rvarad...@jhmi.edu


----- Original Message -----
From: Ravi Varadhan <rvarad...@jhmi.edu>
Date: Thursday, October 29, 2009 10:23 pm
Subject: Re: [R] Fast optimizer
To: R_help Help <rhelp...@gmail.com>
Cc: r-help@r-project.org, r-sig-fina...@stat.math.ethz.ch


> This optimization should not take you 1-2 mins.  My guess is that your 
> coding of the likelihood is inefficient, perhaps containing for loops. 
>  Would you mind sharing your code with us?
> 
> As far as incorporating inequality constraints, there are at least 4 
> approaches:
> 
> 1.  You could use `constrOptim' to incorporate inequality constraints. 
>  
> 
> 2.  I have written a function `constrOptim.nl' that is better than 
> `constrOptim', and it can be used here.
> 
> 3.  The projection method in spg() function in the "BB" package can be 
> used.
> 
> 4.  You can create a penalized objective function, where the 
> inequalities c < a and c < b can be penalized.  Then you can use 
> optim's L-BFGS-B or spg() or nlminb().
> 
> 
> Ravi.
> ____________________________________________________________________
> 
> Ravi Varadhan, Ph.D.
> Assistant Professor,
> Division of Geriatric Medicine and Gerontology
> School of Medicine
> Johns Hopkins University
> 
> Ph. (410) 502-2619
> email: rvarad...@jhmi.edu
> 
> 
> ----- Original Message -----
> From: R_help Help <rhelp...@gmail.com>
> Date: Thursday, October 29, 2009 9:21 pm
> Subject: Re: [R] Fast optimizer
> To: Ravi Varadhan <rvarad...@jhmi.edu>
> Cc: r-help@r-project.org, r-sig-fina...@stat.math.ethz.ch
> 
> 
> > Ok. I have the following likelihood function.
> > 
> > L <- p*dpois(x,a)*dpois(y,b+c)+(1-p)*dpois(x,a+c)*dpois(y,b)
> > 
> > where I have 100 points of (x,y) and parameters c(a,b,c,p) to
> > estimate. Constraints are:
> > 
> > 0 < p < 1
> > a,b,c > 0
> > c < a
> > c < b
> > 
> > I construct a loglikelihood function out of this. First ignoring the
> > last two constraints, it takes optim with box constraint about 1-2 min
> > to estimate this. I have to estimate the MLE on about 200 rolling
> > windows. This will take very long. Is there any faster implementation?
> > 
> > Secondly, I cannot incorporate the last two contraints using optim function.
> > 
> > Thank you,
> > 
> > rc
> > 
> > 
> > 
> > On Thu, Oct 29, 2009 at 9:02 PM, Ravi Varadhan <rvarad...@jhmi.edu> 
> wrote:
> > >
> > > You have hardly given us any information for us to be able to help 
> 
> > you.  Give us more information on your problem, and, if possible, a 
> 
> > minimal, self-contained example of what you are trying to do.
> > >
> > > Ravi.
> > > ____________________________________________________________________
> > >
> > > Ravi Varadhan, Ph.D.
> > > Assistant Professor,
> > > Division of Geriatric Medicine and Gerontology
> > > School of Medicine
> > > Johns Hopkins University
> > >
> > > Ph. (410) 502-2619
> > > email: rvarad...@jhmi.edu
> > >
> > >
> > > ----- Original Message -----
> > > From: R_help Help <rhelp...@gmail.com>
> > > Date: Thursday, October 29, 2009 8:24 pm
> > > Subject: [R] Fast optimizer
> > > To: r-help@r-project.org, r-sig-fina...@stat.math.ethz.ch
> > >
> > >
> > >> Hi,
> > >>
> > >> I'm using optim with box constraints to MLE on about 100 data points.
> > >> It goes quite slow even on 4GB machine. I'm wondering if R has any
> > >> faster implementation? Also, if I'd like to impose
> > >> equality/nonequality constraints on parameters, which package I should
> > >> use? Any help would be appreciated. Thank you.
> > >>
> > >> rc
> > >>
> > >> ______________________________________________
> > >> R-help@r-project.org mailing list
> > >>
> > >> PLEASE do read the posting guide
> > >> and provide commented, minimal, self-contained, reproducible code.
> > >
> 
> ______________________________________________
> R-help@r-project.org mailing list
> 
> PLEASE do read the posting guide 
> and provide commented, minimal, self-contained, reproducible code.
#########################################################################################################################
constrOptim.nl <- function (par, fn, gr=NULL, hin=NULL, hin.jac=NULL, heq=NULL, 
heq.jac=NULL, 
mu = 1e-03, control = list(), eps=1.e-07, itmax=50, trace=TRUE, method="BFGS", 
NMinit=TRUE, ...)  {
# Constrained optimization with nonlinear inequality constraints
# Adaptive barrier MM algorithm (Ken Lange, 1994) for inequalities
# Augmented Lagrangian algorithm (Madsen, Nielsen, Tingeleff, 2004) for 
equalities
#
# par = starting vector of parameter values; initial vector must be "feasible"
# fn = scalar objective function
# gr = gradient function (will be computed using finite-difference, if not 
specified; but computations will be faster if specified)
# hin = a vector function specifying inequality constraints such that hin[j] > 
0 for all j
# hin.jac = jacobian of the inequality vector function (will be computed using 
finite-difference, if not specified; but computations will be faster if 
specified)
# heq = a vector function specifying equality constraints such that heq[j] = 0 
for all j
# heq.jac = jacobian of the equality vector function (will be computed using 
finite-difference, if not specified; but computations will be faster if 
specified)
#
# mu = parameter for barrier penalty
# control = a list of control parameters, same as that used in optim()
# eps = tolerance for convergence of outer iterations of the barrier and/or 
augmented lagrangian algorithm
# itmax = maximum number of outer iterations of the barrier and/or augmented 
lagrangian algorithm
# trace = logical variable indicating whether information on outer iterations 
should be printed out
# method = algorithm in optim() to be used; default is "BFGS" variable metric 
method
# NMinit = logical variable indicating whether "Nelder-Mead" algorithm should 
be used in optim() for the first outer iteration
#
# Author:  Ravi Varadhan, Johns Hopkins University
# Date:  August 20, 2008
#

   if (is.null(heq) & is.null(hin)) stop("This is an unconstrained optimization 
problem - you should use `optim' \n")

        require(numDeriv, quietly=TRUE)
     if (is.null(gr)) gr <- function(par, ...) grad(func=fn, x=par, method= 
"simple", ...)

   if (is.null(hin)) {
    if (is.null(heq.jac) ) heq.jac <- function(par, ...) jacobian(func=heq, 
x=par, method= "simple", ...)
    ans <- auglag(par, fn, gr, heq=heq, heq.jac=heq.jac, control=control, eps = 
eps, trace=trace, method=method, NMinit=NMinit, itmax=itmax, ...)
  }  else if (is.null(heq)) {

    if (is.null(hin.jac)) hin.jac <- function(par, ...) jacobian(func=hin, 
x=par, method= "simple", ...)
    ans <- adpbar(par, fn, gr, hin=hin, hin.jac=hin.jac, mu=mu, control = 
control, eps = eps, itmax=itmax, trace=trace, method=method, NMinit=NMinit, ...)

  }   else  {
    if (is.null(heq.jac) ) heq.jac <- function(par, ...) jacobian(func=heq, 
x=par, method= "simple", ...)
    if (is.null(hin.jac)) hin.jac <- function(par, ...) jacobian(func=hin, 
x=par, method= "simple", ...)
        ans <- alabama(par, fn, gr, hin=hin, hin.jac=hin.jac, heq=heq, 
heq.jac=heq.jac, mu= mu, control = control, 
        eps = eps, itmax=itmax, trace=trace, method=method, NMinit=NMinit, ...)
        }

detach("package:numDeriv")
    return(ans)
}
        
 
#########################################################################################################################
 adpbar <- function (theta, fn, gr=gr, hin=hin, hin.jac=hin.jac, mu = mu, 
control = control, eps = eps, 
 itmax=itmax, trace=trace, method=method, NMinit=NMinit, ...)  {
 # Constrained optimization with nonlinear inequality constraints
 # Adaptive barrier MM algorithm (Ken Lange, 1994)
 # Ravi Varadhan, Johns Hopkins University
 # August 20, 2008
 #
     if (!is.null(control$fnscale) && control$fnscale < 0) 
         mu <- -mu
 
    R <- function(theta, theta.old, ...) {
        gi <- hin(theta, ...)
        if (any(gi < 0)) return(NaN)
        gi.old <- hin(theta.old, ...)
        bar <- sum(gi.old * log(gi) - hin.jac(theta.old, ...) %*% theta)

        if (!is.finite(bar)) 
            bar <- -Inf
      fn(theta, ...) - mu * bar
    }

    dR <- function(theta, theta.old, ...) {
        gi <- hin(theta, ...)
        gi.old <- hin(theta.old, ...)
        hi <- hin.jac(theta.old, ...)         
        dbar <- colSums(hi* gi.old/gi - hi)
        gr(theta, ...) - mu * dbar
    }
   
    if (any(hin(theta, ...) <= 0)) 
        stop("initial value not feasible")

    obj <- fn(theta, ...)
    r <- R(theta, theta, ...)
        feval <- 0
        geval <- 0 

    for (i in 1:itmax) {
        if (trace) {
                cat("par: ", theta, "\n")
                cat("fval: ", obj, "\n")
        }
        obj.old <- obj
        r.old <- r
        theta.old <- theta

        fun <- function(theta, ...) {
            R(theta, theta.old, ...)
        }
        gradient <- function(theta, ...) {
            dR(theta, theta.old, ...)
        }
        
       if ( NMinit & i == 1)  a <- optim(par=theta.old, fn=fun, gr=gradient, 
control = control, method = "Nelder-Mead", ...)
      else a <- optim(par=theta.old, fn=fun, gr=gradient, control = control, 
method = method, ...)
        r <- a$value

#  Here is "absolute" convergence criterion:
        if (is.finite(r) && is.finite(r.old) && abs(r - r.old) < eps) 
            break
        theta <- a$par
        feval <- feval + a$counts[1]
        if (!NMinit | i > 1) geval <- geval + a$counts[2]
        obj <- fn(theta, ...)
        if (obj > obj.old * sign(mu)) 
            break
    }
    if (i == itmax) {
        a$convergence <- 7
        a$message <- "Barrier algorithm ran out of iterations and did not 
converge"
    }
    if (mu > 0 && obj > obj.old) {
        a$convergence <- 11
        a$message <- paste("Objective function increased at outer iteration", 
            i)
    }
    if (mu < 0 && obj < obj.old) {
        a$convergence <- 11
        a$message <- paste("Objective function decreased at outer iteration", 
            i)
    }
    a$outer.iterations <- i
    a$barrier.value <- a$value
    a$value <- fn(a$par, ...)
    a$barrier.value <- a$barrier.value - a$value
    a$counts <- c(feval, geval)  # total number of fevals and gevals in inner 
iterations in BFGS
    a
}

#########################################################################################################################
auglag <- function (theta, fn, gr=gr, heq=heq, heq.jac=heq.jac, control = 
control, eps = eps, 
 itmax=itmax, trace=trace, method=method, NMinit=NMinit, ...)  {
# Constrained optimization with nonlinear equality constraints
# Augmented Lagrangian algorithm (Madsen, Nielsen, Tingeleff, 2004)
# Ravi Varadhan, Johns Hopkins University
# August 20, 2008
#

   if (!is.null(control$fnscale) && control$fnscale < 0) {
                pfact <- -1
        } else pfact <- 1


        ans <- vector("list")
        feval <- 0
        geval <- 0 
        k <- 0
        lam0 <- 0
        sig0 <- 1
        lam <- lam0
        sig <- sig0
        i0 <- heq(theta, ...)
        Kprev <- max(abs(i0))
        K <- Inf

        while (K > eps & k <= itmax) {   # Augmented Lagrangian loop for 
nonlinear "equality" constraintts 

        if (trace) {
        cat("K, lambda, sig: ", K, lam, sig, "\n")
        cat("theta: ", theta, "\n")
        }

        fun <- function(theta, ...) {
                it <- heq(theta, ...)
            fn(theta, ...) - pfact * sum (lam * it) + pfact * sig/2 * sum(it * 
it)
        }
        gradient <- function(theta, ...) {
                it <- heq(theta, ...)
                ij <- heq.jac(theta, ...)
            gr(theta, ...) - pfact * colSums(lam * ij) + pfact * sig * 
drop(t(ij) %*% it)
        }  
        
        if ( NMinit & k == 0 ) a <- optim(par=theta, fn=fun, gr=gradient, 
control = control, method = "Nelder-Mead", ...)
        else a <- optim(par=theta, fn=fun, gr=gradient, control = control, 
method = method, ...)

          theta <- a$par
        r <- a$value
          i0 <- heq(theta, ...)
          K <- max(abs(i0)) 
        feval <- feval + a$counts[1]
          if (!NMinit | k > 0) geval <- geval + a$counts[2]
          k <- k + 1

                if( K <= Kprev/4) {
                        lam <- lam - i0 * sig
                        Kprev <- K
                } else sig <- 10 * sig
        }  # Augmented Lagrangian loop completed

     if (k >= itmax) {
        a$convergence <- 7
        a$message <- "Augmented Lagrangian algorithm ran out of iterations and 
did not converge"
    }
  
    ans$par <- theta
    ans$value <- fn(a$par, ...)
    ans$iterations <- k
    ans$lambda <- lam
    ans$penalty <- r - ans$value
    ans$counts <- c(feval, geval)  # total number of fevals and gevals in inner 
iterations in BFGS

    ans
}
############################################################################################################
alabama <- function (theta, fn, gr=gr, hin=hin, hin.jac=hin.jac, heq=heq, 
heq.jac=heq.jac, mu = mu, control = list(), 
itmax = itmax, eps = eps, trace=trace, method="BFGS", NMinit="FALSE", ...) {
# Constrained optimization with nonlinear inequality constraints
# Augmented Lagrangian Adaptive Barrier MM Algorithm (ALABaMA)
# Ravi Varadhan, Johns Hopkins University
# August 24, 2008
#
# See connection to modified barrier augmented Lagrangian (Goldfarb et al., 
Computational Optimization & Applications 1999)
##########
        if (is.null(heq) & is.null(hin)) stop("This is an unconstrained 
optimization problem - use `optim' \n")

    if (!is.null(control$fnscale) && control$fnscale < 0) {
                mu <- -mu
                pfact <- -1
        } else pfact <- 1

        alpha <- 0.5
        beta <- 1

    R <- function(theta, theta.old, ...) {
        gi <- hin(theta, ...)
        if (any(gi < 0)) return(NaN)
        gi.old <- hin(theta.old, ...)
          hjac <- hin.jac(theta.old, ...)
        bar <- sum(gi.old * log(gi) - hjac %*% theta)

        if (!is.finite(bar)) 
            bar <- -Inf
      fn(theta, ...) - mu * bar
    }

    dR <- function(theta, theta.old, ...) {
        gi <- hin(theta, ...)
        gi.old <- hin(theta.old, ...)
        hjac <- hin.jac(theta.old, ...)         
        dbar <- colSums(hjac* gi.old/gi - hjac)
        gr(theta, ...) - mu * dbar
    }
   
        h0 <- hin(theta, ...)
     if (any(h0 <= 0)) 
        stop("initial value violates inequality constraints")

    obj <- fn(theta, ...)
    r <- R(theta, theta, ...)
        feval <- 0
        geval <- 0 
        lam0 <- 0
        sig0 <- 1
        lam <- lam0
        sig <- sig0
        i0 <- heq(theta, ...)
        Kprev <- max(abs(i0))
        K <- Inf

    for (i in 1:itmax) {  # Adaptive Barrier MM loop for nonlinear "inequality" 
constraintts 
        if (trace) {
                cat("Outer iteration: ", i, "\n")
        cat("K = ", signif(K,2), ", lambda  = ", signif(lam,2), ", Sigma  = ", 
signif(sig,2), "\n ")
                cat("par: ", signif(theta,6), "\n")
                cat("fval =  ", signif(obj,4), "\n \n")
        }
        obj.old <- obj
        r.old <- r
        theta.old <- theta

        fun <- function(theta, ...) {
                it <- heq(theta, ...)
            R(theta, theta.old, ...) - pfact * sum (lam * it) + pfact * sig/2 * 
sum(it * it)
        }
        gradient <- function(theta, ...) {
                it <- heq(theta, ...)
                ij <- heq.jac(theta, ...)
            dR(theta, theta.old, ...) - pfact * colSums(lam * ij) + pfact * sig 
* drop(t(ij) %*% it)
        }  

#       mu <- 1/sig * pfact
        if(sig > 1e05) control$reltol <- 1.e-10

        if ( NMinit & i == 1)  a <- optim(par=theta.old, fn=fun, gr=gradient, 
control = control, method = "Nelder-Mead", ...)
       else a <- optim(par=theta.old, fn=fun, gr=gradient, control = control, 
method = method, ...)

        theta <- a$par
        r <- a$value

          i0 <- heq(theta, ...)
          K <- max(abs(i0))
         feval <- feval + a$counts[1]
        if (!NMinit | i > 1) geval <- geval + a$counts[2]

                if( K <= Kprev/4) {
                        lam <- lam - i0 * sig
                        Kprev <- K
                } else sig <- 10 * sig

        obj <- fn(theta, ...)

 #  Here is "absolute" convergence criterion:
        pconv <- max(abs(theta - theta.old))
        if ((is.finite(r) && is.finite(r.old) && abs(r - r.old) < eps && K < 
eps) | pconv < 1.e-12) {
#        if (is.finite(obj) && is.finite(obj.old) && abs(obj - obj.old) < eps 
&& K < eps) {
                theta.old <- theta
                atemp <- optim(par=theta, fn=fun, gr=gradient, control = 
control, method = "BFGS", hessian=TRUE, ...)
                a$hessian <- atemp$hess 
                break
                }
                
 }

    if (i == itmax) {
        a$convergence <- 7
        a$message <- "ALABaMA ran out of iterations and did not converge"
    } else {
        evals <- eigen(a$hessian)$val
        if (min(evals) < -0.1)  {
        a$convergence <- 8
        a$message <- "Second-order KKT conditions not satisfied"
        } 
        else if (K > eps)  {
        a$convergence <- 9
        a$message <- "Convergence due to lack of progress in parameter updates"
        } 
   }

    a$outer.iterations <- i
    a$lambda <- lam
    a$sigma <- sig
    a$barrier.value <- a$value
    a$value <- fn(a$par, ...)
    a$barrier.value <- a$barrier.value - a$value
    a$K <- K
    a$counts <- c(feval, geval)  # total number of fevals and gevals in inner 
iterations in BFGS
    a
}
##############################################################################################################


______________________________________________
R-help@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.

Reply via email to