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

时间:2018-04-13 09:21:32

标签: r gurobi

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

在@ Paleo13回答之后编辑:正如他所说,他的回答是一个很好的工作。但是,如果有更有效的选择,我也很乐意看到。因此,我加了赏金。有关我所知道的内容,请参阅herehere

可重复的例子:

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

2 个答案:

答案 0 :(得分:2)

您所描述的内容可以使用Solution Pool完成。 Gurobi在8.0版中为解决方案池添加了R API。您set parameters来控制解决方案池;在Solution Pool named components中返回多个解决方案。这在poolsearch.R example中有说明,也可以在examples \ R子目录中找到。

免责声明:我管理Gurobi的技术支持。

答案 1 :(得分:1)

Gurobi 确实可以存储在寻找最佳解决方案时遇到的可行解决方案(或者更确切地说是适合指定的opitmality间隙的解决方案)。这些解决方案存储在&#34;解决方案池中。遗憾的是, gurobi R 包没有访问解决方案池中的解决方案的功能,因此如果我们正在寻找仅使用 R 的解决方案,那么我们就无法使用解决方案池。此外,值得注意的是,解决方案池可能不一定包含所有可行的解决方案,它只包含 Gurobi 在此过程中发现的解决方案,因此如果我们需要所有可行的解决方案,那么我们不能仅仅依靠 Gurobi 的单一运行中的解决方案池。

因此,关于您的问题,一种策略是使用一种称为&#34; Bender&#34;的方法。这基本上涉及解决问题,添加约束以禁止我们刚刚获得的解决方案,然后再次解决问题,并重复此过程,直到没有更可行的解决方案。我编写了一个使用下面的 gurobi R 包实现此方法的函数,并将其应用于您的示例。这种方法可能无法很好地扩展到大量可行解决方案的问题,因为理想情况下我们会访问解决方案池以减少 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))