Emy
Emy

Reputation: 977

R - problem with optim() when passing arguments through a function

I am trying to build a double optimization in R. By double optimization, I mean that there is going to be an inner call, in which I optimize a function called inner_function(), and then an outer call, in which I optimize an outer_function() whose output is computed using the optimization of inner_function().

I can make this work when inner_function() is optimized through optim() and outer_function() takes only one argument and is optimized through optimize():

constructor_function <- function(data, fixed = c(FALSE, FALSE)) {
  params <- fixed
  function(p) {
    params[!fixed] <- p
    a <- data[1]
    b <- data[2]
    c <- data[3]
    d <- data[4]
    e <- params[1]
    f <- params[2]
    ## Calculate something
    tot <- abs(a + b + c + d + e + f)
    return(tot)
  }
}

inner_function <- constructor_function(c(1, 2, 3, 4))

inner_function(c(5, 6))
#> [1] 21

optim(c(0, 0), inner_function)$par
#> [1] -3.454274 -6.545726

sum(optim(c(0, 0), inner_function)$par)
#> [1] -10

outer_function <- function(first_factor) {
  inner_function <- constructor_function(c(first_factor, 2, 3, 4))
  values <- optim(c(0, 0), inner_function)$par
  tot <- sum(values)
  return(tot)
}

# check
outer_function(1)
#> [1] -10

optimize(outer_function, lower = 0, upper = 4)
#> $minimum
#> [1] 3.99994
#> 
#> $objective
#> [1] -12.99994

# check
outer_function(3.99994)
#> [1] -12.99994

But I can't make the double optimization work when the outer function (now called outer_function_args) takes more than one argument, so that it can be optimized only with optim():


outer_function_args <- function(first_factor, second_factor) {
  inner_function <- constructor_function(c(first_factor, second_factor, 3, 4))
  values <- optim(c(0, 0), inner_function)$par
  tot <- sum(values)
  return(tot)
}

outer_function_args(1,2)
#> [1] -10

optim(par=c(0,2), outer_function_args)
#> Error in fn(par, ...): argument "second_factor" is missing, with no default

The error mentions that argument "second_factor" is missing, but outer_function_args is running correctly.

Created on 2021-04-15 by the reprex package (v0.3.0)

Upvotes: 0

Views: 510

Answers (1)

Anders Ellern Bilgrau
Anders Ellern Bilgrau

Reputation: 10253

You need to modify your function to take in the parameters as a vector, like so:

outer_function_args <- function(par) {
  inner_function <- constructor_function(c(par[1], par[2], 3, 4))
  values <- optim(c(0, 0), inner_function)$par
  tot <- sum(values)
  return(tot)
}

outer_function_args(par = c(1, 2)) 
#> [1] -10

optim(par=c(0,2), outer_function_args)
#$par
#[1] 3355434 3355445
#
#$value
#[1] -6710886
#
#$counts
#function gradient 
#     253       NA 
#
#$convergence
#[1] 0
#
#$message
#NULL

From the documentation of optim(par, fn) in help("optim"):

fn   A function to be minimized (or maximized), with first argument the vector of parameters over which minimization is to take place. It should return a scalar result.

Upvotes: 1

Related Questions