CPLEX - 使用不同类型的变量添加惰性约束会导致 InvalidCutException
CPLEX - Adding Lazy Constraints with variables of different type lead to InvalidCutException
我正在求解具有两种类型变量的模型,x[i][j] 是一个 ILOBOOL,u[i] 是一个 ILOFLOAT。我正在尝试向该模型添加惰性约束。我已经设法以下列方式正确添加惰性约束:
std::stringstream name;
IloNumVar** x = new IloNumVar*[ins.n+1];
for(int i = 0; i < ins.n+1; ++i){
x[i] = new IloNumVar[ins.n];
for(int j = 0; j < ins.n; ++j){
if(ins.has_edge(i,j) || i == ins.n){
name << "x_" << i << "_" << j;
x[i][j] = IloNumVar(env,0,1,ILOBOOL, name.str().c_str());
name.str("");
}
}
}
IloNumVar* u = new IloNumVar[ins.n+1];
for(int i = 0; i < ins.n+1; ++i){
name << "u_" << i;
u[i] = IloNumVar(env,(i < ins.n) ? 1 : 0,ins.L+1,ILOFLOAT,name.str().c_str());
name.str("");
}
/*Objective function and some other non-lazy Constraints
*/
cplex.extract(model);
for(int i = 0; i < ins.n; ++i){
for(int j = 0; j < ins.n; ++j){
if(ins.has_edge(i,j)){
IloConstraint edge_con(x[i][j] + x[j][i]<= 1);
name << "edge_" <<i << "_" << j;
edge_con.setName(name.str().c_str());
name.str("");
try{
cplex.addLazyConstraint(edge_con);
}catch(IloCplex::InvalidCutException& ex){
auto con = ex.getCut();
std::cout << ex.getMessage() << " " << ex.getStatus();
std::cout << con << "\n";
}
}
}
}
这段代码工作正常,当我打印 .lp 时,惰性约束就在那里。但是,当我将 IloConstraint edge_con(x[i][j] + x[j][i]<= 1);
更改为 IloConstraint edge_con(x[i][j] + x[j][i] + u[j] <= 1);
时,我收到一条 InvalidCutException: invalid cut -1
消息。为什么抛出这个异常?
将我的评论变成答案:
问题是 CPLEX 不知道惰性约束中引用的 u
变量。
如果添加常规约束,则约束中的所有变量都会自动提取到 CPLEX。对于惰性约束,情况有所不同:变量不会自动提取。因此,如果惰性约束引用了一个未在常规约束或之前的 objective 中使用的变量,那么 CPLEX 将不知道该变量。这将导致无法添加剪切,您将得到您观察到的异常。
要解决此问题,请使用
将 u
变量显式添加到问题中
for (i = 0; i < ins.n+1; ++i)
model.add(u[i]);
(也许对 x
变量做同样的事情)
我正在求解具有两种类型变量的模型,x[i][j] 是一个 ILOBOOL,u[i] 是一个 ILOFLOAT。我正在尝试向该模型添加惰性约束。我已经设法以下列方式正确添加惰性约束:
std::stringstream name;
IloNumVar** x = new IloNumVar*[ins.n+1];
for(int i = 0; i < ins.n+1; ++i){
x[i] = new IloNumVar[ins.n];
for(int j = 0; j < ins.n; ++j){
if(ins.has_edge(i,j) || i == ins.n){
name << "x_" << i << "_" << j;
x[i][j] = IloNumVar(env,0,1,ILOBOOL, name.str().c_str());
name.str("");
}
}
}
IloNumVar* u = new IloNumVar[ins.n+1];
for(int i = 0; i < ins.n+1; ++i){
name << "u_" << i;
u[i] = IloNumVar(env,(i < ins.n) ? 1 : 0,ins.L+1,ILOFLOAT,name.str().c_str());
name.str("");
}
/*Objective function and some other non-lazy Constraints
*/
cplex.extract(model);
for(int i = 0; i < ins.n; ++i){
for(int j = 0; j < ins.n; ++j){
if(ins.has_edge(i,j)){
IloConstraint edge_con(x[i][j] + x[j][i]<= 1);
name << "edge_" <<i << "_" << j;
edge_con.setName(name.str().c_str());
name.str("");
try{
cplex.addLazyConstraint(edge_con);
}catch(IloCplex::InvalidCutException& ex){
auto con = ex.getCut();
std::cout << ex.getMessage() << " " << ex.getStatus();
std::cout << con << "\n";
}
}
}
}
这段代码工作正常,当我打印 .lp 时,惰性约束就在那里。但是,当我将 IloConstraint edge_con(x[i][j] + x[j][i]<= 1);
更改为 IloConstraint edge_con(x[i][j] + x[j][i] + u[j] <= 1);
时,我收到一条 InvalidCutException: invalid cut -1
消息。为什么抛出这个异常?
将我的评论变成答案:
问题是 CPLEX 不知道惰性约束中引用的 u
变量。
如果添加常规约束,则约束中的所有变量都会自动提取到 CPLEX。对于惰性约束,情况有所不同:变量不会自动提取。因此,如果惰性约束引用了一个未在常规约束或之前的 objective 中使用的变量,那么 CPLEX 将不知道该变量。这将导致无法添加剪切,您将得到您观察到的异常。
要解决此问题,请使用
将u
变量显式添加到问题中
for (i = 0; i < ins.n+1; ++i)
model.add(u[i]);
(也许对 x
变量做同样的事情)