Ejemplo n.º 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 */
Ejemplo n.º 2
0
/*
 * The function returns a true value if the tested KKT conditions are
 * satisfied and false otherwise.
 */
static int
checkkkt (CPXCENVptr env, CPXLPptr lp, CPXDIM const *cone, double tol)
{
   CPXDIM cols = CPXXgetnumcols (env, lp);
   CPXDIM rows = CPXXgetnumrows (env, lp);
   CPXDIM qcons = CPXXgetnumqconstrs (env, lp);
   double *dslack = NULL, *pi = NULL, *socppi = NULL;
   double *val = NULL, *rhs = NULL;
   CPXDIM *ind = NULL;
   char *sense = NULL;
   double *x = NULL, *slack = NULL, *qslack = NULL;
   double *sum = NULL;
   qbuf_type qbuf;
   CPXCHANNELptr resc, warnc, errc, logc;
   int ok = 0, skip = 0;
   int status;
   CPXDIM i, j, q;

   qbuf_init (&qbuf);

   /* Get the channels on which we may report. */
   if ( (status = CPXXgetchannels (env, &resc, &warnc, &errc, &logc)) != 0 )
      goto TERMINATE;

   /* Fetch results and problem data that we need to check the KKT
    * conditions.
    */
   CPXXmsg (logc, "Fetching results ... ");
   if ( (cols > 0 && (dslack = malloc (cols * sizeof (*dslack))) == NULL) ||
        (rows > 0 && (pi = malloc (rows * sizeof (*pi))) == NULL) ||
        (qcons > 0 && (socppi = malloc (qcons * sizeof (*socppi))) == NULL) ||
        (cols > 0 && (x = malloc (cols * sizeof (*x))) == NULL) ||
        (rows > 0 && (sense = malloc (rows * sizeof (*sense))) == NULL ) ||
        (rows > 0 && (slack = malloc (rows * sizeof (*slack))) == NULL ) ||
        (qcons > 0 && (qslack = malloc (qcons * sizeof (*qslack))) == NULL) ||
        (cols > 0 && (sum = malloc (cols * sizeof (*sum))) == NULL) ||
        (cols > 0 && (val = malloc (cols * sizeof (*val))) == NULL) ||
        (cols > 0 && (ind = malloc (cols * sizeof (*ind))) == NULL) ||
        (rows > 0 && (rhs = malloc (rows * sizeof (*rhs))) == NULL) )
   {
      CPXXmsg (errc, "Out of memory!\n");
      goto TERMINATE;
   }

   /* Fetch problem data. */
   if ( (status = CPXXgetsense (env, lp, sense, 0, rows - 1)) != 0 )
      goto TERMINATE;
   if ( (status = CPXXgetrhs (env, lp, rhs, 0, rows - 1)) != 0 )
      goto TERMINATE;

   /* Fetch solution information. */
   if ( (status = CPXXgetx (env, lp, x, 0, cols - 1)) != 0 )
      goto TERMINATE;
   if ( (status = CPXXgetpi (env, lp, pi, 0, rows - 1)) != 0 )
      goto TERMINATE;
   if ( (status = getsocpconstrmultipliers (env, lp, dslack, socppi)) != 0 )
      goto TERMINATE;
   if ( (status = CPXXgetslack (env, lp, slack, 0, rows - 1)) != 0 )
      goto TERMINATE;
   if ( (status = CPXXgetqconstrslack (env, lp, qslack, 0, qcons - 1)) != 0 )
      goto TERMINATE;
   CPXXmsg (logc, "ok.\n");

   /* Print out the solution data we just fetched. */
   CPXXmsg (resc, "x      = [");
   for (j = 0; j < cols; ++j)
      CPXXmsg (resc, " %+7.3f", x[j]);
   CPXXmsg (resc, " ]\n");
   CPXXmsg (resc, "dslack = [");
   for (j = 0; j < cols; ++j)
      CPXXmsg (resc, " %+7.3f", dslack[j]);
   CPXXmsg (resc, " ]\n");
   CPXXmsg (resc, "pi     = [");
   for (i = 0; i < rows; ++i)
      CPXXmsg (resc, " %+7.3f", pi[i]);
   CPXXmsg (resc, " ]\n");
   CPXXmsg (resc, "slack  = [");
   for (i = 0; i < rows; ++i)
      CPXXmsg (resc, " %+7.3f", slack[i]);
   CPXXmsg (resc, " ]\n");
   CPXXmsg (resc, "socppi = [");
   for (q = 0; q < qcons; ++q)
      CPXXmsg (resc, " %+7.3f", socppi[q]);
   CPXXmsg (resc, " ]\n");
   CPXXmsg (resc, "qslack = [");
   for (q = 0; q < qcons; ++q)
      CPXXmsg (resc, " %+7.3f", qslack[q]);
   CPXXmsg (resc, " ]\n");

   /* Test primal feasibility. */
   CPXXmsg (logc, "Testing primal feasibility ... ");
   /* This example illustrates the use of dual vectors returned by CPLEX
    * to verify dual feasibility, so we do not test primal feasibility
    * here. */
   CPXXmsg (logc, "ok.\n");

   /* Test dual feasibility.
    * We must have
    * - for all <= constraints the respective pi value is non-negative,
    * - for all >= constraints the respective pi value is non-positive,
    * - since all quadratic constraints are <= constraints the socppi
    *   value must be non-negative for all quadratic constraints,
    * - the dslack value for all non-cone variables must be non-negative.
    * Note that we do not support ranged constraints here.
    */
   CPXXmsg (logc, "Testing dual feasibility ... ");
   for (i = 0; i < rows; ++i) {
      switch (sense[i]) {
      case 'L':
         if ( pi[i] < -tol ) {
            CPXXmsg (errc, "<= row %d has invalid dual multiplier %f.\n",
                     i, pi[i]);
            goto TERMINATE;
         }
         break;
      case 'G':
         if ( pi[i] > tol ) {
            CPXXmsg (errc, ">= row %d has invalid dual multiplier %f.\n",
                     i, pi[i]);
            goto TERMINATE;
         }
         break;
      case 'E':
         /* Nothing to check here. */
         break;
      }
   }
   for (q = 0; q < qcons; ++q) {
      if ( socppi[q] < -tol ) {
         CPXXmsg (errc, "Quadratic constraint %d has invalid dual multiplier %f.\n",
                  q, socppi[q]);
         goto TERMINATE;
      }
   }
   for (j = 0; j < cols; ++j) {
      if ( cone[j] == NOT_IN_CONE && dslack[j] < -tol ) {
         CPXXmsg (errc, "dslack value for column %d is invalid: %f\n", j, dslack[j]);
         goto TERMINATE;
      }
   }
   CPXXmsg (logc, "ok.\n");

   /* Test complementary slackness.
    * For each constraint either the constraint must have zero slack or
    * the dual multiplier for the constraint must be 0. Again, we must
    * consider the special case in which a variable is not explicitly
    * contained in a second order cone constraint (conestat[j] == 0).
    */
   CPXXmsg (logc, "Testing complementary slackness ... ");
   for (i = 0; i < rows; ++i) {
      if ( fabs (slack[i]) > tol && fabs (pi[i]) > tol ) {
         CPXXmsg (errc, "Complementary slackness not satisfied for row %d (%f, %f)\n",
                  i, slack[i], pi[i]);
         goto TERMINATE;
      }
   }
   for (q = 0; q < qcons; ++q) {
      if ( fabs (qslack[q]) > tol && fabs (socppi[q]) > tol ) {
         CPXXmsg (errc, "Complementary slackness not satisfied for cone %d (%f, %f).\n",
                  q, qslack[q], socppi[q]);
         goto TERMINATE;
      }
   }
   for (j = 0; j < cols; ++j) {
      if ( cone[j] == NOT_IN_CONE ) {
         if ( fabs (x[j]) > tol && fabs (dslack[j]) > tol ) {
            CPXXmsg (errc, "Complementary slackness not satisfied for non-cone variable %f (%f, %f).\n",
                     j, x[j], dslack[j]);
            goto TERMINATE;
         }
      }
   }
   CPXXmsg (logc, "ok.\n");

   /* Test stationarity.
    * We must have
    *  c - g[i]'(X)*pi[i] = 0
    * where c is the objective function, g[i] is the i-th constraint of the
    * problem, g[i]'(x) is the derivate of g[i] with respect to x and X is the
    * optimal solution.
    * We need to distinguish the following cases:
    * - linear constraints g(x) = ax - b. The derivative of such a
    *   constraint is g'(x) = a.
    * - second order constraints g(x[1],...,x[n]) = -x[1] + |(x[2],...,x[n])|
    *   the derivative of such a constraint is
    *     g'(x) = (-1, x[2]/|(x[2],...,x[n])|, ..., x[n]/|(x[2],...,x[n])|
    *   (here |.| denotes the Euclidean norm).
    * - bound constraints g(x) = -x for variables that are not explicitly
    *   contained in any second order cone constraint. The derivative for
    *   such a constraint is g'(x) = -1.
    * Note that it may happen that the derivative of a second order cone
    * constraint is not defined at the optimal solution X (this happens if
    * X=0). In this case we just skip the stationarity test.
    */
   CPXXmsg (logc, "Testing stationarity ... ");
   /* Initialize sum = c. */
   if ( (status = CPXXgetobj (env, lp, sum, 0, cols - 1)) != 0 )
      goto TERMINATE;

   /* Handle linear constraints. */
   for (i = 0; i < rows; ++i) {
      CPXNNZ nz, surplus, beg;
      CPXNNZ n;

      status = CPXXgetrows (env, lp, &nz, &beg, ind, val, cols, &surplus,
                            i, i);
      if ( status != 0 )
         goto TERMINATE;
      for (n = 0; n < nz; ++n) {
         sum[ind[n]] -= pi[i] * val[n];
      }
   }
   /* Handle second order cone constraints. */
   for (q = 0; q < qcons; ++q) {
      double norm = 0.0;
      CPXNNZ n;

      if ( !getqconstr (env, lp, q, &qbuf) )
         goto TERMINATE;

      for (n = 0; n < qbuf.qnz; ++n) {
         if ( qbuf.qval[n] > 0 )
            norm += x[qbuf.qcol[n]] * x[qbuf.qcol[n]];
      }
      norm = sqrt (norm);
      if ( fabs (norm) <= tol ) {
         CPXXmsg (warnc, "WARNING: Cannot test stationarity at non-differentiable point.\n");
         skip = 1;
         break;
      }

      for (n = 0; n < qbuf.qnz; ++n) {
         if ( qbuf.qval[n] < 0 )
            sum[qbuf.qcol[n]] -= socppi[q];
         else
            sum[qbuf.qcol[n]] += socppi[q] * x[qbuf.qcol[n]] / norm;
      }
   }
   /* Handle variables that do not appear in any second order cone constraint.
    */
   for (j = 0; !skip && j < cols; ++j) {
      if ( cone[j] == NOT_IN_CONE ) {
         sum[j] -= dslack[j];
      }
   }

   /* Now test that all the entries in sum[] are 0.
    */
   for (j = 0; !skip && j < cols; ++j) {
      if ( fabs (sum[j]) > tol ) {
         CPXXmsg (errc, "Stationarity not satisfied at index %d: %f\n",
                  j, sum[j]);
         goto TERMINATE;
      }
   }
   CPXXmsg (logc, "ok.\n");

   CPXXmsg (logc, "KKT conditions are satisfied.\n");

   ok = 1;
 TERMINATE:
   if ( !ok )
      CPXXmsg (logc, "failed.\n");
   qbuf_clear (&qbuf);
   free (rhs);
   free (ind);
   free (val);
   free (sum);
   free (qslack);
   free (slack);
   free (sense);
   free (x);
   free (socppi);
   free (pi);
   free (dslack);

   return ok;
}
Ejemplo n.º 3
0
static int CPXPUBLIC 
rounddownheur (CPXCENVptr env,
               void       *cbdata,
               int        wherefrom, 
               void       *cbhandle,
               double     *objval_p,
               double     *x,
               int        *checkfeas_p,
               int        *useraction_p)
{
   int status = 0;
   
   int       j, cols;
   double    roundobjval;
   int       *feas = NULL;
   CPXCLPptr lp;
   double    *objcoefs = NULL;

   *useraction_p = CPX_CALLBACK_DEFAULT;

   /* Heuristic motivated by knapsack constrained problems.
      Rounding down all fractional values will give an integer
      solution that is feasible, since all constraints are <= 
      with positive coefficients */

   status = CPXXgetcallbacklp (env, cbdata, wherefrom, &lp);
   if ( status ) {
      fprintf (stdout, "Can't get lp pointer.");
      goto TERMINATE;
   }

   cols = CPXXgetnumcols (env, lp);
   if ( cols <= 0 ) {
      fprintf (stdout, "numcols = %d.", cols);
      status = CPXERR_CALLBACK;
      goto TERMINATE;
   }
   
   objcoefs = malloc (cols * sizeof (*objcoefs));
   feas     = malloc (cols * sizeof (*feas));
   if ( objcoefs == NULL || feas == NULL ) {
      fprintf (stdout, "Out of memory.");
      status = CPXERR_CALLBACK;
      goto TERMINATE;
   } 
 
   status = CPXXgetobj (env, lp, objcoefs, 0, cols-1);
   if ( status ) {
      fprintf (stdout, "Can't get objective.");
      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;
   }

   roundobjval = *objval_p;
   for (j = 0; j < cols; j++) {

      /* Set the fractional variable to zero and update
         the objective value */

      if ( feas[j] == CPX_INTEGER_INFEASIBLE ) {
         roundobjval -= x[j] * objcoefs[j];
         x[j] = 0.0;
      }
   }
   *objval_p = roundobjval;

   /* Have CPLEX check the solution for integer feasibility */

   *checkfeas_p = 1;

   /* Tell CPLEX that a solution is being returned */

   *useraction_p = CPX_CALLBACK_SET;

TERMINATE:

   free_and_null ((char **) &objcoefs);
   free_and_null ((char **) &feas);  

   return (status);

} /* END rounddown */
Ejemplo n.º 4
0
int
main (int argc, char *argv[])
{
   CPXENVptr env = NULL;
   CPXLPptr  lp = NULL;
   int       status = 0;
   CPXDIM    j;
   CPXDIM    numcols;
   double    totinv; 

   int       solstat;
   double    objval;
   double    *x = NULL;

   double    rrhs[1];
   char      rsense[1];
   CPXNNZ    rmatbeg[1];

   CPXDIM    *indices = NULL;
   double    *values = NULL;
   char      *namestore = NULL;
   char      **nameptr = NULL;
   CPXSIZE   surplus, storespace;

   const char * datadir = argc <= 1 ? "../../../examples/data" : argv[1];
   char *prod = NULL;

   prod = (char *) malloc (strlen (datadir) + 1 + strlen("prod.lp") + 1);
   sprintf (prod, "%s/prod.lp", datadir);

   /* Initialize the CPLEX environment */

   env = CPXXopenCPLEX (&status);

   /* If an error occurs, the status value indicates the reason for
      failure.  A call to CPXXgeterrorstring will produce the text of
      the error message.  Note that CPXXopenCPLEX produces no output,
      so the only way to see the cause of the error is to use
      CPXXgeterrorstring.  For other CPLEX routines, the errors will
      be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON.  */

   if ( env == NULL ) {
      char  errmsg[CPXMESSAGEBUFSIZE];
      fprintf (stderr, "Could not open CPLEX environment.\n");
      CPXXgeterrorstring (env, status, errmsg);
      fprintf (stderr, "%s", errmsg);
      goto TERMINATE;
   }

   /* Turn on output to the screen */

   status = CPXXsetintparam (env, CPXPARAM_ScreenOutput, CPX_ON);
   if ( status ) {
      fprintf (stderr, 
               "Failure to turn on screen indicator, error %d.\n", status);
      goto TERMINATE;
   }

   /* Create the problem, using the filename as the problem name */

   lp = CPXXcreateprob (env, &status, "prod.lp");

   /* A returned pointer of NULL may mean that not enough memory
      was available or there was some other problem.  In the case of 
      failure, an error message will have been written to the error 
      channel from inside CPLEX.  In this example, the setting of
      the parameter CPXPARAM_ScreenOutput causes the error message to
      appear on stdout.  Note that most CPLEX routines return
      an error code to indicate the reason for failure.   */

   if ( lp == NULL ) {
      fprintf (stderr, "Failed to create LP.\n");
      goto TERMINATE;
   }

   /* Now read the file, and copy the data into the created lp */

   status = CPXXreadcopyprob (env, lp, prod, NULL);
   if ( status ) {
      fprintf (stderr, "Failed to read and copy the problem data.\n");
      goto TERMINATE;
   }

   /* Tell presolve to do only primal reductions,
      turn off simplex logging */

   status = CPXXsetintparam (env, CPXPARAM_Preprocessing_Reduce, 1);
   if ( status ) {
      fprintf (stderr, "Failed to set CPXPARAM_Preprocessing_Reduce: %d\n", status);
      goto TERMINATE;
   }
   status = CPXXsetintparam (env, CPXPARAM_Simplex_Display, 0);
   if ( status ) {
      fprintf (stderr, "Failed to set CPXPARAM_Simplex_Display: %d\n", status);
      goto TERMINATE;
   } 


   /* Optimize the problem and obtain solution. */

   status = CPXXlpopt (env, lp);
   if ( status ) {
      fprintf (stderr, "Failed to optimize profit LP.\n");
      goto TERMINATE;
   }

   solstat = CPXXgetstat (env, lp);
   status  = CPXXgetobjval (env, lp, &objval);

   if ( status || solstat != CPX_STAT_OPTIMAL ) {
      fprintf (stderr, "Solution failed. Status %d, solstat %d.\n",
               status, solstat);
      goto TERMINATE;
   }
   printf ("Profit objective value is %g\n", objval);


   /* Allocate space for column names */

   numcols = CPXXgetnumcols (env, lp);
   if ( !numcols ) {
      fprintf (stderr, "No columns in problem\n");
      goto TERMINATE;
   }

   CPXXgetcolname (env, lp, NULL, NULL, 0, &surplus, 0, numcols-1);
   storespace = - surplus;

   namestore = malloc (storespace * sizeof(*namestore));
   nameptr   = malloc (numcols * sizeof(*nameptr));
   if ( namestore == NULL  ||  nameptr == NULL ) {
      fprintf (stderr, "No memory for column names\n");
      goto TERMINATE;
   }
 
   status = CPXXgetcolname (env, lp, nameptr, namestore, storespace,
                           &surplus, 0, numcols-1);
   if ( status ) {
      fprintf (stderr, "Failed to get column names\n");
      goto TERMINATE;
   }

   /* Allocate space for solution */

   x = malloc (numcols * sizeof(*x));

   if ( x == NULL ) {
      fprintf (stderr,"No memory for solution.\n");
      goto TERMINATE;
   }

   status = CPXXgetx (env, lp, x, 0, numcols-1);
   if ( status ) {
      fprintf (stderr, "Failed to obtain primal solution.\n");
      goto TERMINATE;
   }

   totinv = 0;
   for (j = 0; j < numcols; j++) {
      if ( !strncmp (nameptr[j], "inv", 3) )  totinv += x[j];
   }
   printf ("Inventory level under profit objective is %g\n", totinv);

   /* Allocate space for a constraint */

   indices = malloc (numcols * sizeof (*indices));
   values  = malloc (numcols * sizeof (*values));

   if ( indices == NULL  ||  values == NULL ) {
      fprintf (stderr, "No memory for constraint\n");
      goto TERMINATE;
   }

   /* Get profit objective and add it as a constraint */

   status = CPXXgetobj (env, lp, values, 0, numcols-1);
   if ( status ) {
      fprintf (stderr,
              "Failed to get profit objective.  Status %d\n", status);
      goto TERMINATE;
   }
   for (j = 0; j < numcols; j++) {
      indices[j] = j;
   }

   rrhs[0]    = objval - fabs (objval) * 1e-6;
   rsense[0]  = 'G';
   rmatbeg[0] = 0;

   status = CPXXpreaddrows (env, lp, 1, numcols, rrhs, rsense,
                           rmatbeg, indices, values, NULL);

   if ( status ) {
      fprintf (stderr,
              "Failed to add objective as constraint.  Status %d\n",
              status);
      goto TERMINATE;
   }

   /* Set up objective to maximize negative of sum of inventory */

   totinv = 0;
   for (j = 0; j < numcols; j++) {
      if ( strncmp (nameptr[j], "inv", 3) ) {
         values[j] = 0.0;
      }
      else {
         values[j] = - 1.0;
      }
   }

   status = CPXXprechgobj (env, lp, numcols, indices, values);

   if ( status ) {
      fprintf (stderr,
              "Failed to change to inventory objective.  Status %d\n",
              status);
      goto TERMINATE;
   }

   status = CPXXlpopt (env, lp);
   if ( status ) {
      fprintf (stderr, "Optimization on inventory level failed. Status %d.\n",
              status);
      goto TERMINATE;
   }

   solstat = CPXXgetstat (env, lp);
   status  = CPXXgetobjval (env, lp, &objval);
   if ( status  ||  solstat != CPX_STAT_OPTIMAL ) {
      fprintf (stderr, "Solution failed. Status %d, solstat %d.\n",
               status, solstat);
      goto TERMINATE;
   }

   printf ("Inventory level after optimization is %g\n", -objval);


   status = CPXXgetx (env, lp, x, 0, numcols-1);
   if ( status ) {
      fprintf (stderr, "Failed to obtain primal solution.\n");
      goto TERMINATE;
   }

   /* Write out the solution */
   printf("Solution status: %d", solstat);
   printf ("\n");
   for (j = 0; j < numcols; j++) {
      printf ( "%s:  Value = %17.10g\n", nameptr[j], x[j]);
   }


TERMINATE:

   /* Free the filename */

   free_and_null ((char **) &prod);

   /* Free up the basis and solution */

   free_and_null ((char **) &indices);
   free_and_null ((char **) &values);
   free_and_null ((char **) &nameptr);
   free_and_null ((char **) &namestore);
   free_and_null ((char **) &x);


   /* Free up the problem, if necessary */

   if ( lp != NULL ) {
      status = CPXXfreeprob (env, &lp);
      if ( status ) {
         fprintf (stderr, "CPXXfreeprob failed, error code %d.\n", status);
      }
   }

   /* Free up the CPLEX environment, if necessary */

   if ( env != NULL ) {
      status = CPXXcloseCPLEX (&env);

      /* Note that CPXXcloseCPLEX produces no output,
         so the only way to see the cause of the error is to use
         CPXXgeterrorstring.  For other CPLEX routines, the errors will
         be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */

      if ( status ) {
         char  errmsg[CPXMESSAGEBUFSIZE];
         fprintf (stderr, "Could not close CPLEX environment.\n");
         CPXXgeterrorstring (env, status, errmsg);
         fprintf (stderr, "%s", errmsg);
      }
   }
     
   return (status);

}  /* END main */