Try our new documentation site (beta).
Filter Content By
Version
Text Search
${sidebar_list_label} - Back
Filter by Language
callback_c.c
/* Copyright 2024, Gurobi Optimization, LLC */ /* This example reads a model from a file, sets up a callback that monitors optimization progress and implements a custom termination strategy, and outputs progress information to the screen and to a log file. The termination strategy implemented in this callback stops the optimization of a MIP model once at least one of the following two conditions have been satisfied: 1) The optimality gap is less than 10% 2) At least 10000 nodes have been explored, and an integer feasible solution has been found. Note that termination is normally handled through Gurobi parameters (MIPGap, NodeLimit, etc.). You should only use a callback for termination if the available parameters don't capture your desired termination criterion. */ #include <stdlib.h> #include <stdio.h> #include <math.h> #include "gurobi_c.h" /* Define structure to pass my data to the callback function */ struct callback_data { double lastiter; double lastnode; double *solution; FILE *logfile; }; /* Define my callback function */ int __stdcall mycallback(GRBmodel *model, void *cbdata, int where, void *usrdata) { struct callback_data *mydata = (struct callback_data *) usrdata; if (where == GRB_CB_POLLING) { /* Ignore polling callback */ } else if (where == GRB_CB_PRESOLVE) { /* Presolve callback */ int cdels, rdels; GRBcbget(cbdata, where, GRB_CB_PRE_COLDEL, &cdels); GRBcbget(cbdata, where, GRB_CB_PRE_ROWDEL, &rdels); if (cdels || rdels) { printf("%7d columns and %7d rows are removed\n", cdels, rdels); } } else if (where == GRB_CB_SIMPLEX) { /* Simplex callback */ double itcnt, obj, pinf, dinf; int ispert; char ch; GRBcbget(cbdata, where, GRB_CB_SPX_ITRCNT, &itcnt); if (itcnt - mydata->lastiter >= 100) { mydata->lastiter = itcnt; GRBcbget(cbdata, where, GRB_CB_SPX_OBJVAL, &obj); GRBcbget(cbdata, where, GRB_CB_SPX_ISPERT, &ispert); GRBcbget(cbdata, where, GRB_CB_SPX_PRIMINF, &pinf); GRBcbget(cbdata, where, GRB_CB_SPX_DUALINF, &dinf); if (ispert == 0) ch = ' '; else if (ispert == 1) ch = 'S'; else ch = 'P'; printf("%7.0f %14.7e%c %13.6e %13.6e\n", itcnt, obj, ch, pinf, dinf); } } else if (where == GRB_CB_MIP) { /* General MIP callback */ double nodecnt, objbst, objbnd, actnodes, itcnt; int solcnt, cutcnt; GRBcbget(cbdata, where, GRB_CB_MIP_NODCNT, &nodecnt); GRBcbget(cbdata, where, GRB_CB_MIP_OBJBST, &objbst); GRBcbget(cbdata, where, GRB_CB_MIP_OBJBND, &objbnd); GRBcbget(cbdata, where, GRB_CB_MIP_SOLCNT, &solcnt); if (nodecnt - mydata->lastnode >= 100) { mydata->lastnode = nodecnt; GRBcbget(cbdata, where, GRB_CB_MIP_NODLFT, &actnodes); GRBcbget(cbdata, where, GRB_CB_MIP_ITRCNT, &itcnt); GRBcbget(cbdata, where, GRB_CB_MIP_CUTCNT, &cutcnt); printf("%7.0f %7.0f %8.0f %13.6e %13.6e %7d %7d\n", nodecnt, actnodes, itcnt, objbst, objbnd, solcnt, cutcnt); } if (fabs(objbst - objbnd) < 0.1 * (1.0 + fabs(objbst))) { printf("Stop early - 10%% gap achieved\n"); GRBterminate(model); } if (nodecnt >= 10000 && solcnt) { printf("Stop early - 10000 nodes explored\n"); GRBterminate(model); } } else if (where == GRB_CB_MIPSOL) { /* MIP solution callback */ double nodecnt, obj; int solcnt; GRBcbget(cbdata, where, GRB_CB_MIPSOL_NODCNT, &nodecnt); GRBcbget(cbdata, where, GRB_CB_MIPSOL_OBJ, &obj); GRBcbget(cbdata, where, GRB_CB_MIPSOL_SOLCNT, &solcnt); GRBcbget(cbdata, where, GRB_CB_MIPSOL_SOL, mydata->solution); printf("**** New solution at node %.0f, obj %g, sol %d, x[0] = %.2f ****\n", nodecnt, obj, solcnt, mydata->solution[0]); } else if (where == GRB_CB_MIPNODE) { int status; /* MIP node callback */ printf("**** New node ****\n"); GRBcbget(cbdata, where, GRB_CB_MIPNODE_STATUS, &status); if (status == GRB_OPTIMAL) { GRBcbget(cbdata, where, GRB_CB_MIPNODE_REL, mydata->solution); GRBcbsolution(cbdata, mydata->solution, NULL); } } else if (where == GRB_CB_BARRIER) { /* Barrier callback */ int itcnt; double primobj, dualobj, priminf, dualinf, compl; GRBcbget(cbdata, where, GRB_CB_BARRIER_ITRCNT, &itcnt); GRBcbget(cbdata, where, GRB_CB_BARRIER_PRIMOBJ, &primobj); GRBcbget(cbdata, where, GRB_CB_BARRIER_DUALOBJ, &dualobj); GRBcbget(cbdata, where, GRB_CB_BARRIER_PRIMINF, &priminf); GRBcbget(cbdata, where, GRB_CB_BARRIER_DUALINF, &dualinf); GRBcbget(cbdata, where, GRB_CB_BARRIER_COMPL, &compl); printf("%d %.4e %.4e %.4e %.4e %.4e\n", itcnt, primobj, dualobj, priminf, dualinf, compl); } else if (where == GRB_CB_IIS) { int constrmin, constrmax, constrguess, boundmin, boundmax, boundguess; GRBcbget(cbdata, where, GRB_CB_IIS_CONSTRMIN, &constrmin); GRBcbget(cbdata, where, GRB_CB_IIS_CONSTRMAX, &constrmax); GRBcbget(cbdata, where, GRB_CB_IIS_CONSTRGUESS, &constrguess); GRBcbget(cbdata, where, GRB_CB_IIS_BOUNDMIN, &boundmin); GRBcbget(cbdata, where, GRB_CB_IIS_BOUNDMAX, &boundmax); GRBcbget(cbdata, where, GRB_CB_IIS_BOUNDGUESS, &boundguess); printf("IIS: %d,%d,%d %d,%d,%d\n", constrmin, constrmax, constrguess, boundmin, boundmax, boundguess); } else if (where == GRB_CB_MESSAGE) { /* Message callback */ char *msg; GRBcbget(cbdata, where, GRB_CB_MSG_STRING, &msg); fprintf(mydata->logfile, "%s", msg); } return 0; } int main(int argc, char *argv[]) { GRBenv *env = NULL; GRBmodel *model = NULL; int error = 0; int numvars, solcount, optimstatus, j; double objval, x; char *varname; struct callback_data mydata; mydata.lastiter = -GRB_INFINITY; mydata.lastnode = -GRB_INFINITY; mydata.solution = NULL; mydata.logfile = NULL; if (argc < 2) { fprintf(stderr, "Usage: callback_c filename\n"); goto QUIT; } /* Open log file */ mydata.logfile = fopen("cb.log", "w"); if (!mydata.logfile) { fprintf(stderr, "Cannot open cb.log for callback message\n"); goto QUIT; } /* Create environment */ error = GRBloadenv(&env, NULL); if (error) goto QUIT; /* Turn off display and heuristics */ error = GRBsetintparam(env, GRB_INT_PAR_OUTPUTFLAG, 0); if (error) goto QUIT; error = GRBsetdblparam(env, GRB_DBL_PAR_HEURISTICS, 0.0); if (error) goto QUIT; /* Read model from file */ error = GRBreadmodel(env, argv[1], &model); if (error) goto QUIT; /* Allocate space for solution */ error = GRBgetintattr(model, GRB_INT_ATTR_NUMVARS, &numvars); if (error) goto QUIT; mydata.solution = malloc(numvars*sizeof(double)); if (mydata.solution == NULL) { fprintf(stderr, "Failed to allocate memory\n"); exit(1); } /* Set callback function */ error = GRBsetcallbackfunc(model, mycallback, (void *) &mydata); if (error) goto QUIT; /* Solve model */ error = GRBoptimize(model); if (error) goto QUIT; /* Capture solution information */ printf("\nOptimization complete\n"); error = GRBgetintattr(model, GRB_INT_ATTR_SOLCOUNT, &solcount); if (error) goto QUIT; error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimstatus); if (error) goto QUIT; if (solcount == 0) { printf("No solution found, optimization status = %d\n", optimstatus); goto QUIT; } error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &objval); if (error) goto QUIT; printf("Solution found, objective = %.4e\n", objval); for ( j = 0; j < numvars; ++j ) { error = GRBgetstrattrelement(model, GRB_STR_ATTR_VARNAME, j, &varname); if (error) goto QUIT; error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, j, &x); if (error) goto QUIT; if (x != 0.0) { printf("%s %f\n", varname, x); } } QUIT: /* Error reporting */ if (error) { printf("ERROR: %s\n", GRBgeterrormsg(env)); exit(1); } /* Close log file */ if (mydata.logfile) fclose(mydata.logfile); /* Free solution */ if (mydata.solution) free(mydata.solution); /* Free model */ GRBfreemodel(model); /* Free environment */ GRBfreeenv(env); return 0; }