Esempio n. 1
0
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 */
Esempio n. 2
0
static int CPXPUBLIC
solvecallback (CPXCENVptr env,
               void       *cbdata,
               int        wherefrom,
               void       *userinfo,
               int        *useraction_p)
{
   int status = 0;

   int      lpstatus = 0;
   CPXLPptr nodelp   = NULL;
   double   *prex    = NULL;
   MYCBptr  mycbinfo = (MYCBptr) userinfo;
   CPXLPptr mip      = mycbinfo->mip;
   double   *relx    = mycbinfo->relx;
   CPXDIM   cols;
   int      prestat;

   *useraction_p = CPX_CALLBACK_DEFAULT;

   /* Only use callback for solving the root relaxation (node 0) */

   if ( mycbinfo->count > 0 ) {
      goto TERMINATE;
   }
   mycbinfo->count++;

   /* Extract the LP to be solved */

   status = CPXXgetcallbacknodelp (env, cbdata, wherefrom, &nodelp);
   if ( status ) goto TERMINATE;

   cols = CPXXgetnumcols (env, nodelp);

   prex = malloc (cols * sizeof (*prex));
   if ( prex == NULL ) {
      status = CPXERR_NO_MEMORY;
      goto TERMINATE;
   }

   /* Use MIP presolve to crush the original solution.  Note that
      MIP presolve can only crush primal solutions */

   status = CPXXgetprestat (env, mip, &prestat, NULL, NULL, NULL,
                           NULL);
   if ( status ) goto TERMINATE;

   /* If a presolved model exists, then relx is crushed down
      to prex, the corresponding solution for the presolved
      model; otherwise, prex is just a copy of relx */
   
   if ( prestat ) {
      status = CPXXcrushx (env, mip, relx, prex);
      if ( status ) goto TERMINATE;
   }
   else {
      memcpy (prex, relx, cols * sizeof (*relx));
   }

   /* Feed the crushed solution into 'nodelp' */

   status = CPXXcopystart (env, nodelp, NULL, NULL, prex, NULL,
                          NULL, NULL);

   /* Use primal to reoptimize, since we only have a primal
      solution */

   status = CPXXprimopt (env, nodelp);
   if ( status )  goto TERMINATE;

   lpstatus = CPXXgetstat (env, nodelp);
   if ( lpstatus == CPX_STAT_OPTIMAL        ||
        lpstatus == CPX_STAT_OPTIMAL_INFEAS ||
        lpstatus == CPX_STAT_INFEASIBLE       ) {
      *useraction_p = CPX_CALLBACK_SET;
   }
   
TERMINATE:

   free_and_null ((char **) &prex);

   return (status);

} /* END solvecallback */
Esempio n. 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 */