示例#1
0
static int CPXPUBLIC
usersetbranch (CPXCENVptr   env,
               void         *cbdata,
               int          wherefrom,
               void         *cbhandle,
               int          brtype,
               CPXDIM       sos,
               int          nodecnt,
               CPXDIM       bdcnt,
               const CPXDIM *nodebeg,
               const CPXDIM *indices,
               const char   *lu,
               const double *bd,
               const double *nodeest,
               int          *useraction_p)   
{
   int status = 0;
 
   CPXDIM   j, bestj = -1;
   CPXDIM   cols;
   double   maxobj = -CPX_INFBOUND;
   double   maxinf = -CPX_INFBOUND;
   double   xj_inf;
   double   xj_lo;
   double   objval;
   double   *x   = NULL;
   double   *obj = NULL;
   int      *feas = NULL;
 
   char     varlu[1];
   double   varbd[1];
   CPXCNT   seqnum1, seqnum2;
 
   CPXCLPptr lp;
 
   /* Initialize useraction to indicate no user action taken */
 
   *useraction_p = CPX_CALLBACK_DEFAULT;
 
   /* If CPLEX is choosing an SOS branch, take it */
 
   if ( sos >= 0 )  return (status);
 
   /* Get pointer to the problem */
 
   status = CPXXgetcallbacklp (env, cbdata, wherefrom, &lp);
   if ( status ) {
      fprintf (stdout, "Can't get LP pointer.\n");
      goto TERMINATE;
   }
 
   cols = CPXXgetnumcols (env, lp);
   if ( cols <= 0 ) {
      fprintf (stdout, "Can't get number of columns.\n");
      status = CPXERR_CALLBACK;
      goto TERMINATE;
   }
 
   /* Get solution values and objective coefficients */
 
   x    = malloc (cols * sizeof (*x));
   obj  = malloc (cols * sizeof (*obj));
   feas = malloc (cols * sizeof (*feas));
   if ( x     == NULL ||
        obj   == NULL ||
        feas  == NULL   ) {
      fprintf (stdout, "Out of memory.");
      status = CPXERR_CALLBACK;
      goto TERMINATE;
   }
 
   status = CPXXgetcallbacknodex (env, cbdata, wherefrom, x, 0,
                                  cols-1);
   if ( status ) {
      fprintf (stdout, "Can't get node solution.");
      goto TERMINATE;
   }
 
   status = CPXXgetcallbacknodeobjval (env, cbdata, wherefrom,
                                       &objval);
   if ( status ) {
      fprintf (stdout, "Can't get node objective value.");
      goto TERMINATE;
   }
 
   status = CPXXgetobj (env, lp, obj, 0, cols-1);
   if ( status ) {
      fprintf (stdout, "Can't get obj.");
      goto TERMINATE;
   }
 
   status = CPXXgetcallbacknodeintfeas (env, cbdata, wherefrom, feas,
                                        0, cols-1);
   if ( status ) {
      fprintf (stdout,
               "Can't get variable feasible status for node.");
      goto TERMINATE;
   }
 
   /* Branch on var with largest objective coefficient among those
      with largest infeasibility */
 
   for (j = 0; j < cols; j++) {
      if ( feas[j] == CPX_INTEGER_INFEASIBLE ) {
         xj_inf = x[j] - floor (x[j]);
         if ( xj_inf > 0.5 )  xj_inf = 1.0 - xj_inf;
 
         if ( xj_inf >= maxinf                            &&
              (xj_inf > maxinf || fabs (obj[j]) >= maxobj)  ) {
            bestj  = j;
            maxinf = xj_inf; 
            maxobj = fabs (obj[j]);
         }
      }
   }
 
   /* If there weren't any eligible variables, take default branch */
 
   if ( bestj < 0 ) {
      goto TERMINATE;
   }
 
   /* Now set up node descriptions */
 
   xj_lo = floor (x[bestj]);
 
   /* Up node */
 
   varlu[0] = 'L';
   varbd[0] = xj_lo + 1;
   status = CPXXbranchcallbackbranchbds (env, cbdata, wherefrom,
                                        1, &bestj, varlu, varbd,
                                        objval, NULL, &seqnum1);
   if ( status )  goto TERMINATE;
 
   /* Down node */
 
   varlu[0] = 'U';
   varbd[0] = xj_lo;
 
   status = CPXXbranchcallbackbranchbds (env, cbdata, wherefrom,
                                         1, &bestj, varlu, varbd,
                                         objval, NULL, &seqnum2);
   if ( status )  goto TERMINATE;
 
   /* Set useraction to indicate a user-specified branch */
 
   *useraction_p = CPX_CALLBACK_SET;
 
TERMINATE:
 
   free_and_null ((char **) &x);
   free_and_null ((char **) &obj);
   free_and_null ((char **) &feas); 
   return (status);
 
} /* END usersetbranch */
示例#2
0
static int CPXPUBLIC 
mycutcallback (CPXCENVptr env,
               void       *cbdata,
               int        wherefrom,
               void       *cbhandle,
               int        *useraction_p)
{
   int status = 0;

   CUTINFOptr cutinfo = (CUTINFOptr) cbhandle;

   CPXDIM   numcols  = cutinfo->numcols;
   CPXDIM   numcuts  = cutinfo->num;
   double   *x       = cutinfo->x;
   CPXNNZ   *beg     = cutinfo->beg;
   CPXDIM   *ind     = cutinfo->ind;
   double   *val     = cutinfo->val;
   double   *rhs     = cutinfo->rhs;
   CPXDIM   *cutind  = NULL;
   double   *cutval  = NULL;
   double   cutvio;
   int      addcuts = 0;
   CPXDIM   i, j;
   CPXNNZ   k;
   CPXDIM   cutnz;

   *useraction_p = CPX_CALLBACK_DEFAULT; 

   status = CPXXgetcallbacknodex (env, cbdata, wherefrom, x,
                                 0, numcols-1); 
   if ( status ) {
      fprintf(stderr, "Failed to get node solution.\n");
      goto TERMINATE;
   }

   for (i = 0; i < numcuts; i++) {
      cutvio = -rhs[i];
      k = beg[i];
      cutnz = beg[i+1] - k;
      cutind = ind + k;
      cutval = val + k;
      for (j = 0; j < cutnz; j++) {
         cutvio += x[cutind[j]] * cutval[j];
      }

      /* Use a cut violation tolerance of 0.01 */

      if ( cutvio > 0.01 ) { 
         status = CPXXcutcallbackadd (env, cbdata, wherefrom,
                                     cutnz, rhs[i], 'L',
                                     cutind, cutval, 1);
         if ( status ) {
            fprintf (stderr, "Failed to add cut.\n");
            goto TERMINATE;
         }
         addcuts++;
      }
   }

   /* Tell CPLEX that cuts have been created */ 
   if ( addcuts > 0 ) {
      *useraction_p = CPX_CALLBACK_SET; 
   }

TERMINATE:

   return (status);

} /* END mycutcallback */
示例#3
0
static int CPXPUBLIC 
benders_callback  (CPXCENVptr env, void *cbdata, int wherefrom, 
                   void *cbhandle, int *useraction_p) 
{
   int status = 0;
   int do_separate = 0;
   USER_CBHANDLE *user_cbhandle = (USER_CBHANDLE *) cbhandle;
   
   /* Data structures to add the Benders' cut */
   
   CPXDIM k, nzcnt, cur_x_col, cur_v_col, cur_u_col;
   int worker_lp_sol_stat, sense, purgeable;
   double rhs;
   double eps_ray = 1e-03;
   

   *useraction_p = CPX_CALLBACK_DEFAULT;
   
   /* Decide if we want to separate cuts, depending on 
      the parameter wherefrom */

   switch (wherefrom) {
      case CPX_CALLBACK_MIP_CUT_FEAS: 
         do_separate = 1; 
         break;
      case CPX_CALLBACK_MIP_CUT_LAST: 
         do_separate = 1;
         break;
      case CPX_CALLBACK_MIP_CUT_LOOP: 
         do_separate = 0;
         break;
      default:
         fprintf (stderr, "Unexpected value of wherefrom: %d\n", wherefrom);
         do_separate = 0;
   }

   if( !do_separate ) goto TERMINATE; 

   /* Get the current x solution */
   
   status = CPXXgetcallbacknodex (env, cbdata, wherefrom, user_cbhandle->x, 
                                  0, user_cbhandle->num_x_cols-1);
   if ( status ) {
      fprintf (stderr, "Error in CPXXgetcallbacknodex: status = %d\n", status);
      goto TERMINATE;
   }

   /* Update the objective function in the worker LP:
      minimize sum(k in V0) sum((i,j) in A) x(i,j) * v(k,i,j) 
               - sum(k in V0) u(k,0) + sum(k in V0) u(k,k)    */
     
   for (k = 1; k < user_cbhandle->num_nodes; ++k) {
      for (cur_x_col = 0; cur_x_col < user_cbhandle->num_x_cols; ++cur_x_col) {
         user_cbhandle->indices[cur_x_col] = (k-1) * user_cbhandle->num_x_cols + 
                                             cur_x_col;
      }
      status = CPXXchgobj(user_cbhandle->env, user_cbhandle->lp, 
                          user_cbhandle->num_x_cols, 
                          user_cbhandle->indices, 
                          user_cbhandle->x);
      if ( status ) {
         fprintf (stderr, "Error in CPXXchgobj: status = %d\n", status);
         goto TERMINATE;
      }
   }

   /* Solve the worker LP and look for a violated cut 
      A violated cut is available iff 
      worker_lp_sol_stat == CPX_STAT_UNBOUNDED */

   status = CPXXprimopt (user_cbhandle->env, user_cbhandle->lp);
   if ( status ) {
      fprintf (stderr, "Error in CPXXprimopt: status = %d\n", status);
      goto TERMINATE;
   }
   worker_lp_sol_stat = CPXXgetstat (user_cbhandle->env, user_cbhandle->lp);
   if ( worker_lp_sol_stat != CPX_STAT_UNBOUNDED) 
      goto TERMINATE;
   
   /* Get the violated cut as an unbounded ray of the worker LP */

   status = CPXXgetray (user_cbhandle->env, user_cbhandle->lp, user_cbhandle->ray);
   if ( status ) {
      fprintf (stderr, "Error in CPXXgetray: status = %d\n", status);
      goto TERMINATE;
   }

   /* Compute the cut from the unbounded ray. The cut is:
      sum((i,j) in A) (sum(k in V0) v(k,i,j)) * x(i,j) >= 
      sum(k in V0) u(k,0) - u(k,k)  */

   nzcnt = 0;
   for (cur_x_col = 0; cur_x_col < user_cbhandle->num_x_cols; ++cur_x_col) {
      user_cbhandle->cutind[nzcnt] = cur_x_col;
      user_cbhandle->cutval[nzcnt] = 0.;
      for (k = 1; k < user_cbhandle->num_nodes; ++k) {
         cur_v_col = (k-1) * user_cbhandle->num_x_cols + cur_x_col;
         if ( user_cbhandle->ray[cur_v_col] > eps_ray ) {
            user_cbhandle->cutval[nzcnt] += user_cbhandle->ray[cur_v_col];
         }
      }
      if ( user_cbhandle->cutval[nzcnt] > eps_ray ) {
         ++nzcnt;
      }
   }

   sense = 'G';
   rhs = 0.;   
   for (k = 1; k < user_cbhandle->num_nodes; ++k) {
      cur_u_col = user_cbhandle->num_v_cols + (k-1) * user_cbhandle->num_nodes;
      if ( fabs (user_cbhandle->ray[cur_u_col]) > eps_ray ) {
         rhs += user_cbhandle->ray[cur_u_col];
      }
      cur_u_col = user_cbhandle->num_v_cols + (k-1) * user_cbhandle->num_nodes + k;
      if ( fabs (user_cbhandle->ray[cur_u_col]) > eps_ray ) {
         rhs -= user_cbhandle->ray[cur_u_col];
      }
   }
   
   purgeable = CPX_USECUT_FORCE;

   /* With this choice of the purgeable parameter,
      the cut is added to the current relaxation and
      it cannot be purged.
      Note that the value CPX_USECUT_FILTER is not allowed if
      Benders' cuts are added as lazy constraints (i.e., if 
      wherefrom is CPX_CALLBACK_MIP_CUT_LOOP or 
      CPX_CALLBACK_MIP_CUT_LAST). 
      Possible values and meaning of the purgeable parameter 
      are illustrated in the documentation of CPXcutcallbackadd */
   
   /* Add the cut to the master ILP */
      
   status = CPXXcutcallbackadd (env, cbdata, wherefrom, nzcnt, rhs, sense, 
                                user_cbhandle->cutind, user_cbhandle->cutval,
                                purgeable);
   if ( status ) {
      fprintf (stderr, "Error in CPXXcutcallbackadd: status = %d\n", status);
      goto TERMINATE;
   }
   
   /* Tell CPLEX that cuts have been created */ 

   *useraction_p = CPX_CALLBACK_SET; 

TERMINATE:

   /* If an error has been encountered, we fail */

   if ( status ) *useraction_p = CPX_CALLBACK_FAIL; 

   return status;

} /* END benders_callback */
示例#4
0
static int CPXPUBLIC 
mycutcallback (CPXCENVptr env,
               void       *cbdata,
               int        wherefrom,
               void       *cbhandle,
               int        *useraction_p)
{
   int status = 0;

   CUTINFOptr cutinfo = (CUTINFOptr) cbhandle;

   CPXDIM   numcols  = cutinfo->numcols;
   CPXDIM   numcuts  = cutinfo->num;
   double   *x       = cutinfo->x;
   CPXNNZ   *beg     = cutinfo->beg;
   CPXDIM   *ind     = cutinfo->ind;
   double   *val     = cutinfo->val;
   double   *rhs     = cutinfo->rhs;
   CPXDIM   *cutind  = NULL;
   double   *cutval  = NULL;
   double   cutvio;
   int      addedcuts = 0;
   CPXDIM   i, j;
   CPXNNZ   k;
   CPXDIM   cutnz;

   *useraction_p = CPX_CALLBACK_DEFAULT; 

   /* If we are called as a user cut callback, decide
      first if we want to add cuts or abort the cut loop.
      When adding user cuts with purgeable flag set to 
      CPX_USECUT_PURGE or CPX_USECUT_FILTER, it is important 
      to avoid the possibility of an infinite cut loop, where 
      the same cuts are added to the LP and then immediately 
      purged at every cut pass. Such a situation can be avoided,
      for instance, by applying a tailing off criterion and aborting 
      the cut loop where no progress in the objval is observed.
      Note, however, that the same approach must not be applied
      with lazy constraints. In this case, if lazy constraints are
      added with purgeable flag set to CPX_USECUT_PURGE, adding
      the same lazy constraint more than once could be required
      to ensure the correctness of the final result. */

   if ( wherefrom == CPX_CALLBACK_MIP_CUT_LOOP ||
        wherefrom == CPX_CALLBACK_MIP_CUT_LAST   ) {
      CPXCNT oldnodeid     = cutinfo->nodeid;
      double oldnodeobjval = cutinfo->nodeobjval;

      /* Retrieve nodeid and node objval of the current node */

      status = CPXXgetcallbacknodeinfo (env, cbdata, wherefrom, 0,
                                        CPX_CALLBACK_INFO_NODE_SEQNUM_LONG,
                                        &cutinfo->nodeid);
      if ( status ) {
         fprintf(stderr, "Failed to get node id.\n");
         goto TERMINATE;
      }

      status = CPXXgetcallbacknodeinfo (env, cbdata, wherefrom, 0,
                                        CPX_CALLBACK_INFO_NODE_OBJVAL,
                                        &cutinfo->nodeobjval);
      if ( status ) {
         fprintf(stderr, "Failed to get node objval.\n");
         goto TERMINATE;
      }

      /* Abort the cut loop if we are stuck at the same node
         as before and there is no progress in the node objval */

      if ( oldnodeid == cutinfo->nodeid ) {
         double objchg = (cutinfo->nodeobjval - oldnodeobjval);
         /* Multiply objchg by objsen to normalize 
            the change in the objective function to 
            the case of a minimization problem */
         objchg *= cutinfo->objsen;
         if ( objchg <= EPSOBJ ) {
            *useraction_p = CPX_CALLBACK_ABORT_CUT_LOOP;
            goto TERMINATE;
         }
      }
   }

   /* If we reached this point, we are 
      .. in a lazyconstraint callback, or 
      .. in a user cut callback, and cuts seem to help 
         improving the node objval. 
      In both cases, we retrieve the x solution and 
      look for violated cuts. */

   status = CPXXgetcallbacknodex (env, cbdata, wherefrom, x,
                                 0, numcols-1); 
   if ( status ) {
      fprintf(stderr, "Failed to get node solution.\n");
      goto TERMINATE;
   }

   for (i = 0; i < numcuts; i++) {
      cutvio = -rhs[i];
      k = beg[i];
      cutnz = beg[i+1] - k;
      cutind = ind + k;
      cutval = val + k;
      for (j = 0; j < cutnz; j++) {
         cutvio += x[cutind[j]] * cutval[j];
      }

      /* Use a cut violation tolerance of 0.01 */

      if ( cutvio > 0.01 ) { 
         status = CPXXcutcallbackadd (env, cbdata, wherefrom,
                                     cutnz, rhs[i], 'L',
                                     cutind, cutval, CPX_USECUT_PURGE);
         if ( status ) {
            fprintf (stderr, "Failed to add cut.\n");
            goto TERMINATE;
         }
         addedcuts++;
      }
   }

   /* Tell CPLEX that cuts have been created */ 
   if ( addedcuts > 0 ) {
      *useraction_p = CPX_CALLBACK_SET; 
   }

TERMINATE:

   return (status);

} /* END mycutcallback */