Solution violates the lazy constraint added in callback
Hi all,
I’m using a C++ callback to enforce a set of constraints as lazy constraints. When Gurobi finds an incumbent solution, my callback detects a violated inequality and adds it via addLazy(). However, Gurobi still finishes and returns a solution that violates that same (most recently added) lazy constraint.
Has anyone seen this behavior before? Any help would be greatly appreciated.
minimal snippet:
int Model::solve(bool logging)
{
try
{
pricing_model->set(GRB_IntParam_LazyConstraints, 1);
pricing_model->set(GRB_IntParam_PreCrush, 1);
pricing_model->setCallback(this->cutgen);
pricing_model->optimize();
//Here it output the solution that violates the latest lazy constraint that my callback added.
int status = pricing_model->get(GRB_IntAttr_Status);
if (status == GRB_OPTIMAL || status == GRB_TIME_LIMIT || status == GRB_SUBOPTIMAL) {
int solCount = pricing_model->get(GRB_IntAttr_SolCount);
if (solCount > 0) {
double obj = pricing_model->get(GRB_DoubleAttr_ObjVal);
std::cout << "Obj = " << obj << "\n";
for (long u = 0; u < n; ++u) {
for (long c = 0; c < num_s; ++c) {
double val = x[u][c].get(GRB_DoubleAttr_X);
std::cout << "x[" << u << "][" << c << "] = " << val << "\n";
}
}
} else {
std::cout << "No feasible solution found.\n";
}
}
}
}
void CutGenerator::callback()
{
try
{
if (where == GRB_CB_MIPSOL)
{
x_val = new double *[n];
for (long u = 0; u < n; ++u) {
x_val[u] = this->getSolution(x_vars[u], num_s);
}
if (CLEAN_VARS_BEYOND_PRECISION)
clean_x_val_beyond_precision(SEPARATION_PRECISION);
run_lazy_constraint_separation(ADD_LAZY_CNTRS);
for (long u=0; u < n; u++)
delete[] x_val[u];
delete[] x_val;
}
else if (where == GRB_CB_MIPNODE)
{
if (this->getIntInfo(GRB_CB_MIPNODE_STATUS) != GRB_OPTIMAL)
return;
x_val = new double*[n];
for (long u = 0; u < n; ++u)
x_val[u] = this->getNodeRel(x_vars[u], num_s);
run_separation_alg_of_other_cuts(ADD_USER_CUTS);
if (CLEAN_VARS_BEYOND_PRECISION)
clean_x_val_beyond_precision(SEPARATION_PRECISION);
// I tried both addLazy and addCut in MIPNODE, but doesn't change my situation
run_lazy_constraint_separation(ADD_USER_CUTS);
for (long u=0; u < n; u++)
delete[] x_val[u];
delete[] x_val;
}
}
}
bool CutGenerator::run_lazy_constraint_separation(int kind_of_cut)
{
bool model_updated = false;
vector<GRBLinExpr> cuts_lhs = vector<GRBLinExpr>();
vector<long> cuts_rhs = vector<long>();
//this is the separation algorithm that return ture if cuts_lhs.size() > 0
model_updated = separate_lazy_constraint_std(cuts_lhs,cuts_rhs);
if (model_updated)
{
//Here we can see from the output that the violated constraint is correctly identified
for (size_t i = 0; i < cuts_lhs.size(); ++i)
{
std::cout << "cut[" << i << "]: ";
print_expr(cuts_lhs[i]);
std::cout << " <= " << cuts_rhs[i] << "\n";
}
for (unsigned long idx = 0; idx<cuts_lhs.size(); ++idx)
{
if (kind_of_cut == ADD_USER_CUTS){
addCut(cuts_lhs[idx] <= cuts_rhs[idx]);
}
else if (kind_of_cut == ADD_LAZY_CNTRS){
addLazy(cuts_lhs[idx] <= cuts_rhs[idx]);
}
}
}
return model_updated;
}
0
Please sign in to leave a comment.
Comments
0 comments