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 变量做同样的事情)