0

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)

1 Answer 1

1

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.

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

2 Comments

Thank you, it's very helpful.
Glad I could help! :)

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.