简体   繁体   English

如何让Gurobi(使用R)显示所有解决方案

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

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. 正如问题所述:我知道有几种解决方案(参见GA的输出并检查值和约束是否正确),但我无法将它们从Gurobi中取出。

Edit after @Paleo13's answer : As he states, his answer is a good workround. 在@ Paleo13回答之后编辑 :正如他所说,他的回答是一个很好的工作。 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))

What you describe can be done with the Solution Pool . 您所描述的内容可以通过解决方案池完成 Gurobi added the R API for the solution pool in version 8.0. Gurobi在8.0版中为解决方案池添加了R API。 You set parameters to control the solution pool; 您可以设置参数来控制解决方案池; the multiple solutions are returned in the Solution Pool named components . 名为componentsSolution Pool中返回多个解决方案 This is illustrated in the poolsearch.R example , which can also be found in the examples\\R subdirectory. 这在poolsearch.R示例中进行了说明,该示例也可以在examples \\ R子目录中找到。

Disclaimer: I manage technical support for Gurobi. 免责声明:我管理Gurobi的技术支持。

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). Gurobi确实可以存储在寻找最佳解决方案时遇到的可行解决方案(或者更确切地说是符合指定的opitmality间隙的解决方案)。 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. 遗憾的是, gurobi R软件包没有访问解决方案池中的解决方案的功能,因此如果我们正在寻找仅使用R的解决方案,那么我们就无法使用解决方案池。 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 . 此外,值得注意的是,解决方案池可能不一定包含所有可行的解决方案,它只包含Gurobi在此过程中发现的解决方案,因此如果我们需要所有可行的解决方案,那么我们不能仅仅依赖于单个解决方案池古罗比的奔跑

So, with regards to your question, one strategy is to use a method referred to as "Bender's cuts". 因此,关于您的问题,一种策略是使用称为“Bender's cut”的方法。 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. 我编写了一个使用下面的gurobi R包实现此方法的函数,并将其应用于您的示例。 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). 这种方法可能无法很好地扩展到大量可行解决方案的问题,因为理想情况下我们会访问解决方案池以减少Gurobi运行的总数,但这是我所知道的最佳方法(但我很乐意听到)如果有人有任何更好的想法)。

# 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))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM