/* Copyright 2025, Gurobi Optimization, LLC */
/* We find alternative epsilon-optimal solutions to a given knapsack
problem by using PoolSearchMode */
using System;
using Gurobi;
class poolsearch_cs {
static void Main() {
try{
// Sample data
int groundSetSize = 10;
double[] objCoef = new double[] {32, 32, 15, 15, 6, 6, 1, 1, 1, 1};
double[] knapsackCoef = new double[] {16, 16, 8, 8, 4, 4, 2, 2, 1, 1};
double Budget = 33;
int e, status, nSolutions;
// Create environment
GRBEnv env = new GRBEnv("poolsearch_cs.log");
// Create initial model
GRBModel model = new GRBModel(env);
model.ModelName = "poolsearch_cs";
// Initialize decision variables for ground set:
// x[e] == 1 if element e is chosen
GRBVar[] Elem = model.AddVars(groundSetSize, GRB.BINARY);
model.Set(GRB.DoubleAttr.Obj, Elem, objCoef, 0, groundSetSize);
for (e = 0; e < groundSetSize; e++) {
Elem[e].VarName = string.Format("El{0}", e);
}
// Constraint: limit total number of elements to be picked to be at most
// Budget
GRBLinExpr lhs = new GRBLinExpr();
for (e = 0; e < groundSetSize; e++) {
lhs.AddTerm(knapsackCoef[e], Elem[e]);
}
model.AddConstr(lhs, GRB.LESS_EQUAL, Budget, "Budget");
// set global sense for ALL objectives
model.ModelSense = GRB.MAXIMIZE;
// Limit how many solutions to collect
model.Parameters.PoolSolutions = 1024;
// Limit the search space by setting a gap for the worst possible solution that will be accepted
model.Parameters.PoolGap = 0.10;
// do a systematic search for the k-best solutions
model.Parameters.PoolSearchMode = 2;
// save problem
model.Write("poolsearch_cs.lp");
// Optimize
model.Optimize();
// Status checking
status = model.Status;
if (status == GRB.Status.INF_OR_UNBD ||
status == GRB.Status.INFEASIBLE ||
status == GRB.Status.UNBOUNDED ) {
Console.WriteLine("The model cannot be solved " +
"because it is infeasible or unbounded");
return;
}
if (status != GRB.Status.OPTIMAL) {
Console.WriteLine("Optimization was stopped with status {0}", status);
return;
}
// Print best selected set
Console.WriteLine("Selected elements in best solution:");
Console.Write("\t");
for (e = 0; e < groundSetSize; e++) {
if (Elem[e].X < .9) continue;
Console.Write("El{0} ", e);
}
Console.WriteLine();
// Print number of solutions stored
nSolutions = model.SolCount;
Console.WriteLine("Number of solutions found: {0}", nSolutions);
// Print objective values of solutions
for (e = 0; e < nSolutions; e++) {
model.Parameters.SolutionNumber = e;
Console.Write("{0} ", model.PoolObjVal);
if (e%15 == 14) Console.WriteLine();
}
Console.WriteLine();
// Print fourth best set if available
if (nSolutions >= 4) {
model.Parameters.SolutionNumber = 3;
Console.WriteLine("Selected elements in fourth best solution:");
Console.Write("\t");
for (e = 0; e < groundSetSize; e++) {
if (Elem[e].Xn < .9) continue;
Console.Write("El{0} ", e);
}
Console.WriteLine();
}
model.Dispose();
env.Dispose();
} catch (GRBException e) {
Console.WriteLine("Error code: {0}. {1}", e.ErrorCode, e.Message);
}
}
}