Gurobi apparently not respecting parameter PoolSolutions ?
AnsweredConsider the following C++ code, where \(\texttt{m}\) is a \(\texttt{GRBModel}\) object.
m.set(GRB_IntParam_PoolSolutions, 1);
m.optimize();
std::cout << "Status: " << m.get(GRB_IntAttr_Status) << "\n";
std::cout << "Number of solutions in pool: " << m.get(GRB_IntAttr_SolCount) << "\n";
This prints:
Status: 2
Number of solutions in pool: 3
I was under the impression that \(\texttt{SolCount}\) must be 1, if \(\texttt{PoolSolutions}\) is 1.
The documentation of \(\texttt{PoolSolutions}\) says:
Determines how many MIP solutions are stored.
And the documentation of \(\texttt{SolCount}\) says:
Number of stored solutions from the most recent optimization.
Why is Gurobi storing 3 solutions in this example?

Hi Alberto,
The PoolSolutions parameter is used in conjunction with the PoolSearchMode parameter.
As indicated in the PoolSolutions page:For the default value of PoolSearchMode, these are just the solutions that are found along the way in the process of exploring the MIP search tree. For other values of
PoolSearchMode
, this parameter sets a target for how many solutions to find, so larger values will impact performance.e.g. PoolSearchMode=1 or 2.
If you just want the first feasible solution you can use SolutionLimit.
Cheers,
David0 
Hi! Thanks for your answer. Unfortunately, this is not the issue because I get the same behaviour after setting \(\texttt{GRB_IntParam_PoolSearchMode}\) to 1 or 2.
Furthermore, my interpretation of the documentation is the following:
 With PoolSearchMode = 0, you get the best solution found plus possibly other solutions, but there is no specific guarantee of their quality. The total number of solutions is at most PoolSolutions. (This part of my interpretation is "proven false" by my example with PoolSearchMode = 0.)
 With PoolSearchMode = 1, you get the best solution found plus at least PoolSolutions solutions. If the solution pool is smaller than PoolSolutions when optimisation is over, the solver will keep exploring the B&B tree to give you PoolSolutions solutions.
 With PoolSearchMode = 2, you get exactly PoolSolutions solutions, and you have a guarantee that they are the best, the secondbest, the thirdbest, ..., the PoolSolutionsthbest solutions. (This part of my interpretation is "proven false" by my new example when I set PoolSearchMode = 2.)
Finally, just for clarity, let me state what I am trying to achieve: I would like Gurobi to return only one solution, and this solution should be optimal (or if a timeout occurs, the best one it encountered). Therefore, SolutionLimit would not work because it can return potentially suboptimal solutions. To state it differently, I would like the solution pool to have size 1.
Thanks again for the prompt reply!
AS
0 
Hi Alberto,
That is weird.
Could you share the model or a way for us to reproduce this? (what version are you using?)
Or at least the log.Finally, just for clarity, let me state what I am trying to achieve: I would like Gurobi to return only one solution, and this solution should be optimal (or if a timeout occurs, the best one it encountered). Therefore, SolutionLimit would not work because it can return potentially suboptimal solutions. To state it differently, I would like the solution pool to have size 1.
This sounds like our default behaviour (with no additional Pool parameters).
We will return a single solution: the optimal one if available or the best one found within the time limit.Cheers,
David0 
Hi! I discovered what was happening while preparing a minimal working example for you. I was reusing the same model for multiple optimisations, and it turns out that the column pool doesn't get "cleared" unless one calls \(\texttt{m.reset(1)}\). Therefore, the sequence of events was the following:
 Solve the model with other parameters. It populates the solution pool with \(k\) solutions, and it is possible that \(k > 1\).
 Change something in the model (in my case, the objective coefficient of some variables).
 Set \(\texttt{PoolSolutions}\) to 1 (and \(\texttt{PoolSearchMode}\) to 2).
 Optimise.
 The model still contains \(k\) solutions in the pool, but only the first one is from the new optimisation.
Calling \(\texttt{m.reset(1)}\) before step 4 solves the problem. I am not sure if this behaviour is a bug or by design. I was expecting that PoolSolutions = 1 should give exactly one solution, no matter what prior optimisation occurred.
If you want to reproduce the behaviour, here is a sample LP model (although I guess any model that "visits" more than one integer feasible solution would work), and here is some code:
#include <gurobi_c++.h>
#include <cstdlib>
#include <filesystem>
int main() {
std::filesystem::path model_file{"../gurobi.lp"};
GRBEnv env;
GRBModel model{env, model_file};
// Comment this and the "bug" disappears, because it is
// in this first optimisation that the solution pool gets
// filled with >1 column.
model.optimize();
model.set(GRB_IntParam_PoolSolutions, 1);
for(auto&& pool_search_mode : {0, 1, 2}) {
model.set(GRB_IntParam_PoolSearchMode, pool_search_mode);
// Aleternatively, uncomment this and the "bug" also disappears,
// because now the column pool is cleared at each iteration.
// model.reset(1);
model.optimize();
std::cout << "Status: " << model.get(GRB_IntAttr_Status) << "\n";
std::cout << "Number of solutions in pool: " << model.get(GRB_IntAttr_SolCount) << "\n";
std::cout << "\tPoolSolutions: " << model.get(GRB_IntParam_PoolSolutions) << "\n";
std::cout << "\tPoolSearchMode: " << model.get(GRB_IntParam_PoolSearchMode) << "\n";
}
return EXIT_SUCCESS;
}Best,
AS
0 
Hi Alberto,
Thanks for the very clear explanation and code.
I think this is somehow expected, however, I will raise this to the developers to verify.Cheers,
David0 
Hi Alberto,
We discussed this with our developers.
If you optimize the exact same model without a reset, the data structures are reused, and changing the PoolSolutions parameter has no effect. As you observed, calling model.reset() (it is also sufficient to use default parameter of 0 for this call), forces the rebuild of the data structure and the new value of PoolSolutions is considered. So this is intended and the code you shared is an example.However, if you reuse the same model object but change something in the model, for example, the objective coefficients of some variables, a reset should be triggered automatically and the new PoolSolutions parameter should be considered.
Could you please check if you have an example that fulfills the sequence of events you mentioned in your last comment (where in step 2 indeed something is changed)?Thanks,
Marika0 
Hi Marika! Thanks for your answer. I think the following code confirms what you have just written:
#include <gurobi_c++.h>
#include <cstdlib>
#include <filesystem>
int main() {
std::filesystem::path model_file{"../gurobi.lp"};
GRBEnv env{true};
env.set(GRB_IntParam_OutputFlag, 0);
env.set(GRB_IntParam_LogToConsole, 0);
env.start();
GRBModel model{env, model_file};
model.optimize();
GRBVar* variables = model.getVars();
variables[0].set(GRB_DoubleAttr_UB, 0.0);
model.set(GRB_IntParam_PoolSolutions, 1);
for(auto&& pool_search_mode : {0, 1, 2}) {
model.set(GRB_IntParam_PoolSearchMode, pool_search_mode);
model.optimize();
std::cout << "Status: " << model.get(GRB_IntAttr_Status) << "\n";
std::cout << "Number of solutions in pool: " << model.get(GRB_IntAttr_SolCount) << "\n";
std::cout << "\tPoolSolutions: " << model.get(GRB_IntParam_PoolSolutions) << "\n";
std::cout << "\tPoolSearchMode: " << model.get(GRB_IntParam_PoolSearchMode) << "\n";
}
delete variables;
return EXIT_SUCCESS;
}Here I always get 1 column in the pool. In my production code, what was happening was probably that the new objective coefficients happened to be equal to the old ones, so an update of the data structures you mentioned was not triggered. Indeed, changing line \(\texttt{variables[0].set(GRB_DoubleAttr_UB, 0.0);}\) with \(\texttt{variables[0].set(GRB_DoubleAttr_UB, variables[0].get(GRB_DoubleAttr_UB));}\) gets me three columns in the pool instead of one.
Thanks,
AS
0
Please sign in to leave a comment.
Comments
7 comments