/** MIP info callback that is registered with CPLEX. * This callback picks up primal and dual bounds as well as the current * deterministic time. If bounds changed then updated bounds are send * to the master. Deterministic time stamps are always send to the master. */ static int CPXPUBLIC infocallback (CPXCENVptr cbenv, void *cbdata, int wherefrom, void *cbhandle) { CPXCENVptr env = static_cast<CPXCENVptr>(cbhandle); double dual, primal, ts; // Test if we have improved the primal bound and report if so. if ( CPXXgetcallbackinfo (cbenv, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_INTEGER, &primal) == 0 ) { if ( !best.havePrimal || fabs (best.primal - primal) > best.objdiff ) { best.havePrimal = true; best.primal = primal; (void)CPXXsendinfodouble (env, INFO_NEWPRIMAL, 1, &primal); } } // Test if we have improved the dual bound and report if so. if ( CPXXgetcallbackinfo (cbenv, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_REMAINING, &dual) == 0 ) { if ( !best.haveDual || fabs (best.dual - dual) > best.objdiff ) { best.haveDual = true; best.dual = dual; (void)CPXXsendinfodouble (env, INFO_NEWDUAL, 1, &dual); } } // Always report the current deterministic time. if ( CPXXgetdettime (cbenv, &ts) == 0 ) { (void)CPXXsendinfodouble (env, INFO_DETTIME, 1, &ts); } return 0; }
static int CPXPUBLIC timelimcallback (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle) { int status = 0; TIMELIMINFOptr info = (TIMELIMINFOptr) cbhandle; int hasincumbent = 0; status = CPXXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_MIP_FEAS, &hasincumbent); if ( status ) goto TERMINATE; if ( !info->aborted && hasincumbent ) { double gap; double timenow; status = CPXXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_MIP_REL_GAP, &gap); if ( status ) goto TERMINATE; /* Turn the gap into a percentage */ gap *= 100.0; status = CPXXgettime (env, &timenow); if ( status ) goto TERMINATE; if ( timenow - info->timestart > info->timelim && gap < info->acceptablegap ) { fprintf (stderr, "Good enough solution at time %.2fsec, gap = %g%%, quitting\n", timenow - info->timestart, gap); /* callback may be called again during the clean up phase after the abort has been issued, so remember that abort processing has already occurred. */ info->aborted = 1; /* nonzero status causes abort */ status = 1; } } TERMINATE: return (status); } /* END timelimcallback */
static int CPXPUBLIC userselectnode (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle, CPXCNT *nodenum_p, int *useraction_p) { int status = 0; CPXCNT thisnode; CPXCNT nodesleft; CPXCNT bestnode = 0; CPXCNT depth; CPXCNT maxdepth = -1; double siinf; double maxsiinf = 0.0; /* Initialize useraction to indicate no user node selection */ *useraction_p = CPX_CALLBACK_DEFAULT; /* Choose the node with the largest sum of infeasibilities among those at the greatest depth */ status = CPXXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_NODES_LEFT_LONG, &nodesleft); if ( status ) goto TERMINATE; for (thisnode = 0; thisnode < nodesleft; thisnode++) { status = CPXXgetcallbacknodeinfo (env, cbdata, wherefrom, thisnode, CPX_CALLBACK_INFO_NODE_DEPTH_LONG, &depth); if ( !status ) { status = CPXXgetcallbacknodeinfo (env, cbdata, wherefrom, thisnode, CPX_CALLBACK_INFO_NODE_SIINF, &siinf); } if ( status ) break; if ( (depth >= maxdepth) && (depth > maxdepth || siinf > maxsiinf) ) { bestnode = thisnode; maxdepth = depth; maxsiinf = siinf; } } *nodenum_p = bestnode; *useraction_p = CPX_CALLBACK_SET; TERMINATE: return (status); } /* END userselectnode */
static int CPXPUBLIC usersolve (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle, int *useraction_p) { int status = 0; CPXCNT nodecount; CPXLPptr nodelp; *useraction_p = CPX_CALLBACK_DEFAULT; /* Get pointer to LP subproblem */ status = CPXXgetcallbacknodelp (env, cbdata, wherefrom, &nodelp); if ( status ) goto TERMINATE; /* Find out what node is being processed */ status = CPXXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_NODE_COUNT_LONG, &nodecount); if ( status ) goto TERMINATE; /* Solve initial node with primal, others with dual */ if ( nodecount < 1 ) status = CPXXprimopt (env, nodelp); else status = CPXXdualopt (env, nodelp); /* If the solve was OK, set return to say optimization has been done in callback, otherwise return the CPLEX error code */ if ( !status ) *useraction_p = CPX_CALLBACK_SET; TERMINATE: return (status); } /* END usersolve */
/* Log new incumbents if they are at better than the old by a * relative tolerance of 1e-5; also log progress info every * 100 nodes. */ static int CPXPUBLIC logcallback (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle) { int status = 0; LOGINFOptr info = (LOGINFOptr) cbhandle; int hasincumbent = 0; int newincumbent = 0; double dettime; double objval; double bound; double *x = NULL; status = CPXXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_MIP_FEAS, &hasincumbent); if ( status ) goto TERMINATE; if ( hasincumbent ) { status = CPXXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_INTEGER, &objval); if ( status ) goto TERMINATE; if ( fabs(info->lastincumbent - objval) > 1e-5*(1.0 + fabs(objval)) ) { newincumbent = 1; info->lastincumbent = objval; } } status = CPXXgetdettime (env, &dettime); if ( status ) goto TERMINATE; if ( dettime >= info->lastdettime + 1000.0 || newincumbent ) { double walltime; status = CPXXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_REMAINING, &bound); if ( status ) goto TERMINATE; if ( !newincumbent ) info->lastdettime = dettime; status = CPXXgettime (env, &walltime); if ( status ) goto TERMINATE; printf ("Time = %.2f Dettime = %.2f Best objective = %g", walltime - info->timestart, dettime - info->dettimestart, bound); if ( hasincumbent ) printf (" Incumbent objective = %g\n", objval); else printf ("\n"); } if ( newincumbent ) { int j; CPXDIM numcols = info->numcols; x = malloc (numcols*sizeof(*x)); if ( x == NULL ) { status = CPXERR_NO_MEMORY; goto TERMINATE; } status = CPXXgetcallbackincumbent (env, cbdata, wherefrom, x, 0, numcols-1); if ( status ) goto TERMINATE; printf ("New incumbent values:\n"); for (j = 0; j < numcols; j++) { if ( fabs(x[j]) > 1e-6 ) { printf (" Column %d: %g\n", j, x[j]); } } } TERMINATE: free_and_null ((char **) &x); return (status); } /* END logcallback */