How can I make Gurobi (Using R) show all solutions

♀尐吖头ヾ 提交于 2019-12-11 10:13:48

问题


As the question states: I know there are several solutions (see output of GA and check that value and constraints are correct), but I can't get them out of Gurobi.

Edit after @Paleo13's answer: As he states, his answer is a good workround. However I would also love to see, if there is a more efficient option. Therefore, I added a bounty. See here and here for what I know.

Reproducible example:

my_fun <- function(x) {
  f <- sum(model$obj * x)
  penalty <- sum(abs(model$A %*% x - model$rhs))
  return_value <- -f - 1e8 * penalty # sum(model$obj^2) * // 1e7 * 
  return(return_value)
}

model <- structure(
  list(modelsense = "min", 
           obj = c(0, 40, 20, 40, 0, 20, 20, 20, 0), 
           A = structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 1, 0, 0, 1, 
                           1, 0, -1, 0, 0, 0, 0, -1, 1, 0, 0, 1, 0, 0, 0, 0, 
                           0, 0, 0, 0, 1, 0, 1, -1, 0, 0, 1, 0, -1, 0, 1, 0, 
                           0, 1, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0), 
                         .Dim = c(7L, 9L), 
                         .Dimnames = list(
                           c("constraint1", "constraint2", "", "", "", "", ""), 
                           NULL)),
           rhs = c(1, 1, 0, 0, 0, 1, 1), 
           sense = c("=", "=", "=", "=", "=", "=", "="), 
           vtype = "B"), 
      .Names = c("modelsense", "obj", "A", "rhs", "sense", "vtype"))

# Gurobi:
params <- list(OutputFlag = 1, Presolve = 2,  LogToConsole = 1, PoolSearchMode = 2, PoolSolutions = 10)
ilp_result <- gurobi::gurobi(model, params)
print(ilp_result$x)

# GA for cross-check
GA <- GA::ga(type = "binary", fitness = my_fun, nBits = length(model$obj),
             maxiter = 3000, run = 2000, popSize = 10, seed = 12)

# Crosscheck:
summary(GA)

my_fun(ilp_result$x)
my_fun(GA@solution[1, ])
my_fun(GA@solution[2, ])

sum(abs(model$A %*% ilp_result$x - model$rhs))
sum(abs(model$A %*% GA@solution[1, ] - model$rhs))
sum(abs(model$A %*% GA@solution[2, ] - model$rhs))

回答1:


What you describe can be done with the Solution Pool. Gurobi added the R API for the solution pool in version 8.0. You set parameters to control the solution pool; the multiple solutions are returned in the Solution Pool named components. This is illustrated in the poolsearch.R example, which can also be found in the examples\R subdirectory.

Disclaimer: I manage technical support for Gurobi.




回答2:


Gurobi can indeed store feasible solutions it that encounters while searing for the optimal solution (or rather a solution that fits within a specified opitmality gap). These solutions are stored in a "solution pool". Unfortunately, the gurobi R package does not have the functionality to access the solutions in the solution pool, so if we are looking for a solution that just uses R then we cannot use the solution pool. Also, it's worth noting that the solution pool may not necessarily contain all the feasible solutions, it only contains the solutions that Gurobi found along the way, so if we require all the feasible solutions then we cannot just rely on the solution pool in a single run of Gurobi.

So, with regards to your question, one strategy is to use a method referred to as "Bender's cuts". This basically involves solving the problem, adding in constraints to forbid the solution we just obtained, and then solving the problem again, and repeating this process until there aren't any more feasible solutions. I have written a function that implements this method using the gurobi R package below and applied it to your example. This method may not scale very well to problems with a large number of feasible solutions, because ideally we would access the solution pool to reduce the total number of Gurobi runs, but this is the best approach to my knowledge (but I would love to hear if anyone has any better ideas).

# define functions
find_all_feasible_solutions <- function(model, params) {
  # initialize variables
  counter <- 0
  solutions <- list()
  objs <- numeric(0)
  # search for feasible solutions until no more exist
  while (TRUE) {
    # increment counter
    counter <- counter + 1
    # solve problem
    s <- gurobi::gurobi(model, params)
    # break if status indicates that no feasible solution found
    if (s$status %in% c("INFEASIBLE")) break()
    # store set of solutions
    solutions[[counter]] <- s$x
    objs[[counter]] <- s$objval
    # add constraint to forbid solution this solution
    model$rhs <- c(model$rhs, sum(s$x) - 1)
    model$sense <- c(model$sense, "<=")
    model$A <- rbind(model$A, (s$x * 2) - 1)
  }
  # throw error if no feasible sets of solutions found
  if (length(solutions) == 0) {
    stop("no feasible solutions found.")
  }
  # return solutions as matrix
  list(x = do.call(rbind, solutions), obj = objs)
}

# create initial model
model <- list(
  modelsense = "min",
   obj = c(0, 40, 20, 40, 0, 20, 20, 20, 0),
   A = structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 1, 0, 0, 1,
     1, 0, -1, 0, 0, 0, 0, -1, 1, 0, 0, 1, 0, 0, 0, 0,
     0, 0, 0, 0, 1, 0, 1, -1, 0, 0, 1, 0, -1, 0, 1, 0,
     0, 1, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    .Dim = c(7L, 9L),
    .Dimnames = list(c("constraint1", "constraint2", "", "", "", "", ""),
                     NULL)),
  rhs = c(1, 1, 0, 0, 0, 1, 1),
  sense = c("=", "=", "=", "=", "=", "=", "="),
  vtype = "B")

# create parameters
params <- list(OutputFlag = 1, Presolve = 2,  LogToConsole = 1)

# find all feasible solutions
output <- find_all_feasible_solutions(model, params)

# print number of feasible solutions
print(length(output$obj))


来源:https://stackoverflow.com/questions/49813500/how-can-i-make-gurobi-using-r-show-all-solutions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!