Evolutionary-Optimization-Laboratory / rmoo

An R package for multi/many-objective optimization with non-dominated genetic algorithms' family
GNU General Public License v2.0
29 stars 7 forks source link

100 x 100 matrix evaluation #9

Open pnovoa opened 1 year ago

pnovoa commented 1 year ago

Hello, great project. However, I have a question, why at the beginning of the NSGA-II execution, it calls the fitness function with a 100 x 100 matrix? This evaluation causes me problems, because in the implementation of my fitness function I expect a vector of 1xn (n number of dimension) or maybe a matrix of mxn. But no, a 100x100 matrix.

benitezfj commented 1 year ago

Hello, could you share the call you made to the NSGA-II function? rmoo is designed to generate an initial population M with a size equal to the value established in the popSize argument, and the number of decision variables N is equal to the length of the upper argument, which represents the upper bounds vector of the decision variables.

pnovoa commented 1 year ago

Hi, here is the code, from the example you provide in the repository. Following your explanation above, DTLZ1 should be called by passing it an array of dimension m x n, where n is the size of the upper parameter (in this case n=3). However, as you will see when printing x on the first call, rmoo is passing DTLZ1 a 100 x 100 matrix. I have found that this happens (apparently) when the fitness function is first called.


first_call <<- TRUE

DTLZ1 <- function (x, nobj = 3, ...)
{
  if (is.null(dim(x))) {
    x <- matrix(x, 1)
  }

  if(first_call){
    print(dim(x))
    first_call <<- FALSE
  }

  n <- ncol(x)
  y <- matrix(x[, 1:(nobj - 1)], nrow(x))
  z <- matrix(x[, nobj:n], nrow(x))
  g <- 100 * (n - nobj + 1 + rowSums((z - 0.5)^2 - cos(20 *
                                                         pi * (z - 0.5))))
  tmp <- t(apply(y, 1, cumprod))
  tmp <- cbind(t(apply(tmp, 1, rev)), 1)
  tmp2 <- cbind(1, t(apply(1 - y, 1, rev)))
  f <- tmp * tmp2 * 0.5 * (1 + g)
  return(f)
}

result <- rmoo(fitness = DTLZ1,
               type = "real-valued",
               strategy = "NSGA-III",
               lower = c(0,0,0),
               upper = c(1,1,1),
               monitor = FALSE,
               summary = FALSE,
               popSize = 92,
               n_partitions = 12,
               maxiter = 300)
benitezfj commented 1 year ago

I've tested the code and I was unable to reproduce the error. I've made a small modification to the objective function code to include printing the candidate solution along with its dimension in the first evaluation:

DTLZ1 <- function (x, nobj = 3, ...) {
 if (is.null(dim(x))) {
   x <- matrix(x, 1)
 }

 if(first_call_to_objetive_func){
   cat("Dimension:", dim(x), "\n")
   # I printed the evaluated candidate solution for testing
   cat("Solution:", x, "\n")
   first_call_to_objetive_func <<- FALSE
 }

 n <- ncol(x)
 y <- matrix(x[, 1:(nobj - 1)], nrow(x))
 z <- matrix(x[, nobj:n], nrow(x))
 g <- 100 * (n - nobj + 1 + rowSums((z - 0.5)^2 - cos(20 *
                                                        pi * (z - 0.5))))
 tmp <- t(apply(y, 1, cumprod))
 tmp <- cbind(t(apply(tmp, 1, rev)), 1)
 tmp2 <- cbind(1, t(apply(1 - y, 1, rev)))
 f <- tmp * tmp2 * 0.5 * (1 + g)
 return(f)
}

I've also attempted to verify it using the monitor argument (This will print the solution at the end of each generation), and the results consistently match the print statement within the objective function and the parameters specified in the function call.

The monitor function that will be called at the end of each generation:

monitortest <- function(object, number_objectives, ...) {
  iter <- object@iter
  cat("\n", "Iter:", object@iter, "\n")
  if(first_call_to_monitor){
    cat("Pop Size:", nrow(object@population), " ", "Number of Decision Variables:", ncol(object@population))
    first_call_to_monitor <<- FALSE
  }
}
first_call_to_objetive_func <<- TRUE
first_call_to_monitor <<- TRUE
result <- rmoo(fitness = DTLZ1,
              type = "real-valued",
              strategy = "NSGA-III",
              lower = c(0,0,0),
              upper = c(1,1,1),
              monitor = monitortest,
              summary = FALSE,
              nObj=3,
              seed=45,
              popSize = 92,
              n_partitions = 12,
              maxiter = 5)

The candidate solution printed by the objective function in the first evaluation:

Dimension: 1 3
Solution: 0.6333728 0.8823254 0.05823419

And the printing of the monitor function:

Iter: 1
Pop Size: 92   Number of Decision Variables: 3                                                                                                                           Iter: 2

Does this error occur exclusively when using the sample code, or does it also occur with other specific problems?

pnovoa commented 9 months ago

Hi, I have already discovered the cause. I was not passing the "nObj" parameter. Without it, the algorithm assumes that the number of objective function is 100?

When I debugged it, I get to this part in your code:

{ if (is.null(nObj)) { nObj <- ncol(fitness(matrix(10000, ncol = 100, nrow = 100))) }