5

I have a function that evaluates the gradient and output simultaneously. I want to optimize it with respect to an objective function. How do I pass the objective and gradient as a list to optimx? The example below illustrates the problem:

Suppose I want to find the smallest non-negative root of the polynomial x^4 - 3*x^2 + 2*x + 3. Its gradient is 4*x^3 - 6*x + 2. I use the method nlminb in optimx, as shown below.

optimx(par = 100, method = "nlminb", fn = function(x) x^4 - 3*x^2 + 2*x + 3, 
                                     gr=function(x) 4*x^3 - 6*x + 2, lower = 0)

This works fine, and I get the following output:

       p1 value fevals gevals niter convcode kkt1 kkt2 xtimes
nlminb  1     3     27     24    23        0 TRUE TRUE      0

Now suppose I define the function fngr, which returns both the objective and gradient as a list:

fngr <- function(x) {
  fn <- x^4 - 3*x^2 + 2*x + 3
  gr <- 4*x^3 - 6*x + 2
  return (list(fn = fn, gr = gr))
}

I tried to call optimx as follows:

do.call(optimx, c(list(par = 100, lower = 0, method="nlminb"), fngr))

This returned the following error:

Error in optimx.check(par, optcfg$ufn, optcfg$ugr, optcfg$uhess, lower,  : 
  Function provided is not returning a scalar number

What is the right way to define fngr and the call to optimx when I want to pass the objective and gradient as a list?

Thanks.

3
  • I don't think you can really get away from defining fn and gr separately (even if this is obscured like in @42-'s answer). In general, optimisation subroutines will call each function independently of the other, possibly with different arguments. You can't assume that each call to fn can be matched to exactly one call to gr. Commented Mar 16, 2016 at 23:14
  • Noted, thanks for the input. Commented Mar 17, 2016 at 2:10
  • 2
    way late, but I would consider whether it is worth memoizing the functions (there is a memoise package, I think) Commented Apr 23, 2021 at 23:57

1 Answer 1

3

Define a parameter-less function which can deliver the two functions with suitable names ... when called:

> fngr <- function() {
+   fn <- function(x) {x^4 - 3*x^2 + 2*x + 3}
+   gr <- function(x) {4*x^3 - 6*x + 2}
+   return (list(fn = fn, gr = gr))
+ }
> do.call(optimx, c(list(par = 100, lower = 0, method="nlminb"), fngr() ))
                                    notice the need to call it ------^^
       p1 value fevals gevals niter convcode kkt1 kkt2 xtimes
nlminb  1     3     27     24    23        0 TRUE TRUE  0.002

Looking at this 5 years later I can fully understand the confusion. The way that @ user3294195 did it was much more typical. This is not a typical way of passing function objects in R.

The way this works: The fngr-function is returning a list of two unevaluated expressions rather than returning functions per se. When the RHS of each of the items in the pairlist that forms the parameters for the fngr function is encountered the expression is evaluated with the most accessible value of x. This can be demonstrated more clearly with a simpler test:

fnc <- function( x = x, y = x^2){print(x);print(y)}
fnc(x=2:11)
 [1]  2  3  4  5  6  7  8  9 10 11
 [1]   4   9  16  25  36  49  64  81 100 121

Prior to the call: fnc(x=2:11) there happened to be an x vector in the globalenv() that was not == 2:11. So the function did not "see" that value but rather the value that was assigned to the formal x in the call and it then was available when the interpreter tried to evaluate the expression x^2 in the formals.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.