Reputation: 296
I have a model which has 113000 constraints and 127940 variables (28400 continuous and 99540 integer). The problem is that it takes too long to only write the constraints (around 108 seconds). Solving it takes 32 seconds. I intend to solve bigger problems than this and the time needed grows really fast. I think this should not take this long. Is there a way to add constraints faster in C API? I am using GRBaddconstr, which adds constraints one by one. In GUROBI there is another function, which does this by bathces, namely, GRBaddconstrs, but in the documentation it says there is not really much performance difference. In addition, it is quite hard to use GRBaddconstrs.
I am using C API for GUROBI 8.1.0. For example, one constraint set takes more than 50 seconds to write. When I remove only the line, where I add the constraints with GRBaddconstr, it takes less than a second to run the same loop (99400 iterations). My model is too big to attach here, and complcated, but i am adding the loop i mentioned in case it might help.
//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);
Upvotes: 2
Views: 270
Reputation: 76
I believe the issue is that you are giving Gurobi dense versions of your constraints, rather than sparse representations. Consider the following constraint:
error = GRBaddconstr(model, no_variable, ind, val, GRB_LESS_EQUAL, 0, "LOGICAL");
Here, no_variable
equals 127940. Thus, with every call to GRBaddconstr
, you pass Gurobi the coefficient values for all 127940 variables, despite the fact that at most two variables in this constraint will have non-zero coefficient values. This can consume a lot of time if you do it for every constraint. To be more efficient, you should only pass Gurobi index/value information for the variables with non-zero coefficients. Check the documentation for GRBaddconstr for more details on this.
This can be fixed with a few small code changes. Outside of your for
loops, define two arrays of length two that will store indices and values of variables with non-zero coefficients in a particular "logical" constraint:
lInd = (int *) malloc(sizeof(int) * 2);
lVal = (double *) malloc(sizeof(double) * 2);
Then, in your innermost for
loop, set these indices and values appropriately before adding each constraint:
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);
Lastly, note that constraints should have unique names. If constraints have duplicate names, you can run into unexpected behavior when trying to access constraints by name, read/write the model file, etc.
Upvotes: 3