在GUROBI的C API中添加约束花费的时间太长

在GUROBI的C API中添加约束花费的时间太长,c,constraints,gurobi,C,Constraints,Gurobi,我有一个模型,它有113000个约束和127940个变量(28400个连续变量和99540个整数)。问题是只写约束需要太长的时间(大约108秒)。解决它需要32秒。我打算解决比这更大的问题,所需的时间增长非常快。我认为这不应该花这么长时间。有没有办法在C API中更快地添加约束?我使用的是GRBaddconstr,它一个接一个地添加约束。在GUROBI中还有另一个函数,它是由bathces实现的,即GRBaddconstrs,但在文档中它说,实际上没有太大的性能差异。此外,使用GRBaddcon

我有一个模型,它有113000个约束和127940个变量(28400个连续变量和99540个整数)。问题是只写约束需要太长的时间(大约108秒)。解决它需要32秒。我打算解决比这更大的问题,所需的时间增长非常快。我认为这不应该花这么长时间。有没有办法在C API中更快地添加约束?我使用的是GRBaddconstr,它一个接一个地添加约束。在GUROBI中还有另一个函数,它是由bathces实现的,即GRBaddconstrs,但在文档中它说,实际上没有太大的性能差异。此外,使用GRBaddconstrs非常困难

我正在为Gurobi8.1.0使用C API。例如,一个约束集的写入时间超过50秒。当我仅删除行(在其中使用GRBaddconstr添加约束)时,运行同一循环(99400次迭代)所需的时间不到一秒钟。我的模型太大,无法附加到这里,而且复杂,但我正在添加我提到的循环,以防它可能有所帮助

//LOGICAL
                            time ( &rawtime );
                            timeinfo = localtime ( &rawtime );
                            printf("LOGICAL %d:%d:%d\n", timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec);

                            int c=0;
                            int tmp,tmp2,tmp3;
                            int tmp_sabit;
                            int week_start=wk*T;
                            int week_end=(wk+1)*T;
                            for(int i=0;i<orders_length;i++){
                                for(int t = week_start; t < week_end; t++){
                                    tmp_sabit=i*(T*no_scenarios)+(t-week_start)*no_scenarios+B_threshold;
                                    tmp2=(t-week_start)*no_of_terminals+booking[orders[i]].o;
                                    tmp3=(t-week_start+1)*no_of_terminals+booking[orders[i]].d;
                                    for(int w=0;w<no_scenarios;w++){
                                        tmp=tmp_sabit+w;
                                        val[tmp]=1;
                                        if(booking[orders[i]].o>0){

                                            val[tmp2]=-1;
                                            }
                                        else if(t+1<week_end)
                                            {                                   
                                            val[tmp3]=-1;
                                            }
                                        error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
                                        c++;
                                        //Initialise val to 0
                                        val[tmp]=0;
                                        if(booking[orders[i]].o>0){

                                            val[tmp2]=0;
                                            }
                                        else if(t+1<week_end)
                                            {
                                            val[tmp3]=0;
                                            }
                                        //for(int j = 0; j < no_variable; j++){val[j] = 0;}
                                        }
                                    }
                                }
                            error = GRBupdatemodel(model);
//逻辑
时间(&rawtime);
timeinfo=localtime(&rawtime);
printf(“逻辑%d:%d:%d\n”,时间信息->tm\u小时,时间信息->tm\u分钟,时间信息->tm\u秒);
int c=0;
int tmp、tmp2、tmp3;
int tmp_sabit;
周内开始=周*T;
周内结束=(周+1)*T;

对于(int i=0;i),我认为问题是,你给了Gurobi密集的版本约束,而不是稀疏表示。考虑下面的约束:

error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
lInd = (int *) malloc(sizeof(int) * 2);
lVal = (double *) malloc(sizeof(double) * 2);
lInd[0] = tmp_sabit + w;
lVal[0] = 1;

if (booking[orders[i]].o > 0) {
    lInd[1] = tmp2;
    lVal[1] = -1;
}
else if (t+1 < week_end) {                                   
    lInd[1] = tmp3;
    lVal[1] = -1;
}
else {
    lVal[1] = 0;
}

error = GRBaddconstr(model, 2, lInd, lVal, GRB_LESS_EQUAL, 0, NULL);
这里,
no_variable
等于127940。因此,每次调用
GRBaddconstr
,您都会将所有127940个变量的系数值传递给Gurobi,尽管该约束中最多有两个变量的系数值为非零。如果对每个约束执行此操作,则可能会消耗大量时间。为了更有效cient,您应该只传递系数非零的变量的Gurobi索引/值信息。有关此信息的详细信息,请查看

这可以通过一些小的代码更改来解决。在
for
循环之外,定义两个长度为2的数组,用于在特定的“逻辑”约束中存储非零系数变量的索引和值:

error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
lInd = (int *) malloc(sizeof(int) * 2);
lVal = (double *) malloc(sizeof(double) * 2);
lInd[0] = tmp_sabit + w;
lVal[0] = 1;

if (booking[orders[i]].o > 0) {
    lInd[1] = tmp2;
    lVal[1] = -1;
}
else if (t+1 < week_end) {                                   
    lInd[1] = tmp3;
    lVal[1] = -1;
}
else {
    lVal[1] = 0;
}

error = GRBaddconstr(model, 2, lInd, lVal, GRB_LESS_EQUAL, 0, NULL);
然后,在最内层的
for
循环中,在添加每个约束之前,适当地设置这些索引和值:

error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
lInd = (int *) malloc(sizeof(int) * 2);
lVal = (double *) malloc(sizeof(double) * 2);
lInd[0] = tmp_sabit + w;
lVal[0] = 1;

if (booking[orders[i]].o > 0) {
    lInd[1] = tmp2;
    lVal[1] = -1;
}
else if (t+1 < week_end) {                                   
    lInd[1] = tmp3;
    lVal[1] = -1;
}
else {
    lVal[1] = 0;
}

error = GRBaddconstr(model, 2, lInd, lVal, GRB_LESS_EQUAL, 0, NULL);
lInd[0]=tmp_sabit+w;
lVal[0]=1;
if(预订[订单[i]].o>0){
lInd[1]=tmp2;
lVal[1]=-1;
}
如果(t+1<周末){
lInd[1]=tmp3;
lVal[1]=-1;
}
否则{
lVal[1]=0;
}
错误=GRBaddconstr(模型,2,lInd,lVal,GRB_小于等于,0,NULL);

<>最后,注意约束应该具有唯一的名称。如果约束具有重复的名称,当试图通过名称访问约束、读/写模型文件等时,您可能会遇到意外行为。

< P>我相信问题是,您正在给出Gurobi约束的密集版本,而不是稀疏表示。以下限制:

error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
lInd = (int *) malloc(sizeof(int) * 2);
lVal = (double *) malloc(sizeof(double) * 2);
lInd[0] = tmp_sabit + w;
lVal[0] = 1;

if (booking[orders[i]].o > 0) {
    lInd[1] = tmp2;
    lVal[1] = -1;
}
else if (t+1 < week_end) {                                   
    lInd[1] = tmp3;
    lVal[1] = -1;
}
else {
    lVal[1] = 0;
}

error = GRBaddconstr(model, 2, lInd, lVal, GRB_LESS_EQUAL, 0, NULL);
这里,
no_variable
等于127940。因此,每次调用
GRBaddconstr
,您都会将所有127940个变量的系数值传递给Gurobi,尽管该约束中最多有两个变量的系数值为非零。如果对每个约束执行此操作,则可能会消耗大量时间。为了更有效cient,您应该只传递系数非零的变量的Gurobi索引/值信息。有关此信息的详细信息,请查看

这可以通过一些小的代码更改来解决。在
for
循环之外,定义两个长度为2的数组,用于在特定的“逻辑”约束中存储非零系数变量的索引和值:

error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
lInd = (int *) malloc(sizeof(int) * 2);
lVal = (double *) malloc(sizeof(double) * 2);
lInd[0] = tmp_sabit + w;
lVal[0] = 1;

if (booking[orders[i]].o > 0) {
    lInd[1] = tmp2;
    lVal[1] = -1;
}
else if (t+1 < week_end) {                                   
    lInd[1] = tmp3;
    lVal[1] = -1;
}
else {
    lVal[1] = 0;
}

error = GRBaddconstr(model, 2, lInd, lVal, GRB_LESS_EQUAL, 0, NULL);
然后,在最内层的
for
循环中,在添加每个约束之前,适当地设置这些索引和值:

error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
lInd = (int *) malloc(sizeof(int) * 2);
lVal = (double *) malloc(sizeof(double) * 2);
lInd[0] = tmp_sabit + w;
lVal[0] = 1;

if (booking[orders[i]].o > 0) {
    lInd[1] = tmp2;
    lVal[1] = -1;
}
else if (t+1 < week_end) {                                   
    lInd[1] = tmp3;
    lVal[1] = -1;
}
else {
    lVal[1] = 0;
}

error = GRBaddconstr(model, 2, lInd, lVal, GRB_LESS_EQUAL, 0, NULL);
lInd[0]=tmp_sabit+w;
lVal[0]=1;
if(预订[订单[i]].o>0){
lInd[1]=tmp2;
lVal[1]=-1;
}
如果(t+1<周末){
lInd[1]=tmp3;
lVal[1]=-1;
}
否则{
lVal[1]=0;
}
错误=GRBaddconstr(模型,2,lInd,lVal,GRB_小于等于,0,NULL);

最后,请注意约束应具有唯一的名称。如果约束具有重复的名称,则在尝试按名称访问约束、读取/写入模型文件等时,您可能会遇到意外行为。

我知道注释不是这样做的方式,但非常感谢!我的代码现在快了3-4倍!我知道注释不是这样做的方式,但是太感谢了!我的代码现在快了3-4倍!