Complete Program: lpex7.c

The complete program, lpex7.c, appears here or online in the standard distribution.

#include <ilcplex/cplex.h>

/* Bring in the declarations for the string and character functions 
   and malloc */

#include <ctype.h>
#include <stdlib.h>
#include <string.h>

/* Include declarations for functions in this program */

#ifndef  CPX_PROTOTYPE_MIN

static void
   free_and_null (char **ptr),
   usage         (char *progname);

#else

static void
   free_and_null (),
   usage         ();

#endif

#ifndef  CPX_PROTOTYPE_MIN
int
main (int argc, char *argv[])
#else
int
main (argc, argv)
int   argc;
char  *argv[];
#endif
{
   /* Declare and allocate space for the variables and arrays where we will
      store the optimization results including the status, objective value,
      variable values, and basis. */


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


   CPXENVptr     env = NULL;
   CPXLPptr      lp = NULL;
   int           status = 0;
   int           j;
   int           cur_numrows, cur_numcols;
   char          **cur_colname = NULL;
   char          *cur_colnamestore = NULL;
   int           cur_colnamespace;
   int           surplus;
   int           method;

   char          *basismsg;

   /* Check the command line arguments */

   if (( argc != 3 )                           ||
       ( strchr ("podhbn", argv[2][0]) == NULL )   ) {
      usage (argv[0]);
      goto TERMINATE;
   }

   /* Initialize the CPLEX environment */

   env = CPXopenCPLEX (&status);

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

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

   /* Turn on output to the screen */

   status = CPXsetintparam (env, CPX_PARAM_SCRIND, 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 = CPXcreateprob (env, &status, argv[1]);

   /* 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 CPX_PARAM_SCRIND 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 = CPXreadcopyprob (env, lp, argv[1], NULL);
   if ( status ) {
      fprintf (stderr, "Failed to read and copy the problem data.\n");
      goto TERMINATE;
   }

   /* Optimize the problem and obtain solution. */

   switch (argv[2][0]) {
      case 'o':
         method = CPX_ALG_AUTOMATIC;
         break;
      case 'p':
         method = CPX_ALG_PRIMAL;
         break;
      case 'd':
         method = CPX_ALG_DUAL;
         break;
      case 'n':
         method = CPX_ALG_NET;
         break;
      case 'h':
         method = CPX_ALG_BARRIER;
         break;
      case 'b':
         method = CPX_ALG_BARRIER;
         status = CPXsetintparam (env, CPX_PARAM_BARCROSSALG, CPX_ALG_NONE);
         if ( status ) {
            fprintf (stderr, 
                     "Failed to set the crossover method, error %d.\n", 
status);
            goto TERMINATE;
         }
         break;
      default:
         method = CPX_ALG_NONE;
         break;
   }

   status = CPXsetintparam (env, CPX_PARAM_LPMETHOD, method);
   if ( status ) {
      fprintf (stderr, 
               "Failed to set the optimization method, error %d.\n", status);
      goto TERMINATE;
   }
   
   status = CPXlpopt (env, lp);
   if ( status ) {
      fprintf (stderr, "Failed to optimize LP.\n");
      goto TERMINATE;
   }

   solstat = CPXgetstat (env, lp);
   status  = CPXgetobjval (env, lp, &objval);

   if ( status ) {
      fprintf (stderr,"Failed to obtain objective value.\n");
      goto TERMINATE;
   }

   printf ("Solution status %d.  Objective value %.10g\n", 
           solstat, objval);

   /* The size of the problem should be obtained by asking CPLEX what
      the actual size is.  cur_numrows and cur_numcols store the 
      current number of rows and columns, respectively.  */

   cur_numcols = CPXgetnumcols (env, lp);
   cur_numrows = CPXgetnumrows (env, lp);

   /* Allocate space for basis and solution */

   cstat = (int *)    malloc (cur_numcols*sizeof(int));
   rstat = (int *)    malloc (cur_numrows*sizeof(int));
   x     = (double *) malloc (cur_numcols*sizeof(double));

   if ( cstat == NULL || rstat == NULL || x == NULL ) {
      fprintf (stderr,"No memory for basis statuses.\n");
      goto TERMINATE;
   }

   /* If CPXgetbase causes an error, we don't want to see that error
      message on the screen.  So turn off the screen indicator for
      this call, and turn it back on afterwards.  */

   CPXsetintparam (env, CPX_PARAM_SCRIND, CPX_OFF);
   status = CPXgetbase (env, lp, cstat, rstat);
   CPXsetintparam (env, CPX_PARAM_SCRIND, CPX_ON);

   if ( status == CPXERR_NO_BASIS ) {
      printf ("No basis exists.\n");
      free_and_null ((char **) &cstat);
      free_and_null ((char **) &rstat);
   }
   else if ( status ) {
      fprintf (stderr,"Failed to get basis. error %d.\n", status);
      goto TERMINATE;
   }

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

   /* Now get the column names for the problem.  First we determine how
      much space is used to hold the names, and then do the allocation.
      Then we call CPXgetcolname() to get the actual names. */ 

   status = CPXgetcolname (env, lp, NULL, NULL, 0, &surplus, 0,
                           cur_numcols-1);

   if (( status != CPXERR_NEGATIVE_SURPLUS ) &&
       ( status != 0 )                         )  {
      fprintf (stderr, 
               "Could not determine amount of space for column names.\n");
      goto TERMINATE;
   }

   cur_colnamespace = - surplus;
   if ( cur_colnamespace > 0 ) {
      cur_colname      = (char **) malloc (sizeof(char *)*cur_numcols);
      cur_colnamestore = (char *)  malloc (cur_colnamespace);
      if ( cur_colname      == NULL ||
           cur_colnamestore == NULL   ) {
         fprintf (stderr, "Failed to get memory for column names.\n");
         status = -1;
         goto TERMINATE;
      }
      status = CPXgetcolname (env, lp, cur_colname, cur_colnamestore, 
                              cur_colnamespace, &surplus, 0, cur_numcols-1);
      if ( status ) {
         fprintf (stderr, "CPXgetcolname failed.\n");
         goto TERMINATE;
      }
   }
   else {
      printf ("No names associated with problem.  Using Fake names.\n");
   }

   /* Write out the solution */

   for (j = 0; j < cur_numcols; j++) {
      if ( cur_colnamespace > 0 ) {
         printf ("%-16s:  ", cur_colname[j]);
      }
      else {
         printf ("Fake%-6.6d      :  ", j);;
      }
      printf ("%17.10g", x[j]);
      if ( cstat != NULL ) {
         switch (cstat[j]) {
            case CPX_AT_LOWER:
               basismsg = "Nonbasic at lower bound";
               break;
            case CPX_BASIC:
               basismsg = "Basic";
               break;
            case CPX_AT_UPPER:
               basismsg = "Nonbasic at upper bound";
               break;
            case CPX_FREE_SUPER:
               basismsg = "Superbasic, or free variable at zero";
               break;
            default:
               basismsg = "Bad basis status";
               break;
         }
         printf ("  %s",basismsg);
      }
      printf ("\n");
   }

   
TERMINATE:

   /* Free up the basis and solution */

   free_and_null ((char **) &cstat);
   free_and_null ((char **) &rstat);
   free_and_null ((char **) &x);
   free_and_null ((char **) &cur_colname);
   free_and_null ((char **) &cur_colnamestore);

   /* Free up the problem, if necessary */

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

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

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

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

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

}  /* END main */




/* This simple routine frees up the pointer *ptr, and sets *ptr to NULL */

#ifndef  CPX_PROTOTYPE_MIN
static void
free_and_null (char **ptr)
#else
static void
free_and_null (ptr)
char  **ptr;
#endif
{
   if ( *ptr != NULL ) {
      free (*ptr);
      *ptr = NULL;
   }
} /* END free_and_null */ 


#ifndef  CPX_PROTOTYPE_MIN
static void
usage (char *progname)
#else
static void
usage (progname)
char *progname;
#endif
{
   fprintf (stderr,"Usage: %s filename algorithm\n", progname);
   fprintf (stderr,"   where filename is a file with extension \n");
   fprintf (stderr,"      MPS, SAV, or LP (lower case is allowed)\n");
   fprintf (stderr,"   and algorithm is one of the letters\n");
   fprintf (stderr,"      o          default\n");
   fprintf (stderr,"      p          primal simplex\n");
   fprintf (stderr,"      d          dual simplex\n");
   fprintf (stderr,"      n          network simplex\n");
   fprintf (stderr,"      b          barrier\n");
   fprintf (stderr,"      h          barrier with crossover\n");
   fprintf (stderr," Exiting...\n");
} /* END usage */


Previous Page: Complete Program: ilolpex7.cpp  Return to Top Next Page: Using Callbacks