R minimization - reuse objects computed in function in the calculation of gradient

86 Views Asked by At

I want to do gradient-based minimization using a package like 'optim', where my function and gradient are quite complex. As you can see below in a simplified example, f calculates delta which is also necessary to compute for g. Within the same iteration, however, they are the same. Can I do optimization such that I don't need to compute it twice each iteration? It is the result of a fixed point problem with millions of parameters.

Any ideas? Or reference to a package? Thanks


f <- function(par,dt,..){
  delta <- complexfunction(par,dt)
  obj_value <- complexfunction2(par,dt,delta)
  return(obj_value)
  }

g <- function(par,dt){
  delta <- complexfunction(par,dt) #it's the same as computed in the same iteration in f, can i cross reference?
  gradient <- complexfunction4(par, delta)
  return(gradient)
  }

I don't have a error code yet, I just don't know how to do it. Possibly creating a global and updating it each iteration?

3

There are 3 best solutions below

5
Enrico Schumann On

If you have control over the optimization algorithm, you could attach computations as an attribute to par and so pass it between gradient and objective function. For an example of this, see Section "Updating" in the vignette of package neighbours. (I am the maintainer of that package.) If you cannot do this, you could use an environment, as shown e.g. in https://stat.ethz.ch/pipermail/r-devel/2023-August/082759.html .

2
Nir Graham On

experiment/benchmark using memoise (https://cran.r-project.org/web/packages/memoise/index.html)

If the time spent hashing the function inputs is faster than the complexfunction runtime then you might be onto a winner; its an empirical question.

0
user2554330 On

You suggested creating a global. That's generally a bad idea, but you can create f and g in a way that lets them share access to some variables, or create complexfunction in a way that saves results and returns them if inputs are unchanged. Here's an example of the latter:

complexfunction <- local({
  lastargs  <- NULL
  lastvalue <- NULL
  function(par, dt) {
    args <- list(par, dt)
    if (!identical(lastargs, args))
    {
       lastvalue <<- ... some complex calculation ...
       lastargs <<- args
    }
    lastvalue
   }
  })

This is a simple version of memoisation. @NirGraham gave you a more sophisticated version; I think the memoise package retains multiple function values, not just one.