CPLEX 求解过程详解,注释

本代码块是经过注释的,要查看更加精简的,请查看另一篇文章

/* --------------------------------------------------------------------------
 * File: mipex1.c
 * Version 12.4
 * --------------------------------------------------------------------------
 * Licensed Materials - Property of IBM
 * 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55
 * Copyright IBM Corporation 1997, 2011. All Rights Reserved.
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with
 * IBM Corp.
 * --------------------------------------------------------------------------
 */


/* mipex1.c - Entering and optimizing a MIP problem */


/* Bring in the CPLEX function declarations and the C library
   header file stdio.h with the include of cplex.h. */


#include 


/* Bring in the declarations for the string functions */


#include 
#include 


/* Include declaration for function at end of program */


static int
   setproblemdata (char **probname_p, int *numcols_p, int *numrows_p,
                   int *objsen_p, double **obj_p, double **rhs_p,
                   char **sense_p, int **matbeg_p, int **matcnt_p,
                   int **matind_p, double **matval_p,
                   double **lb_p, double **ub_p, char **ctype_p);


static void
   free_and_null (char **ptr);




/* The problem we are optimizing will have 3 rows, 4 columns
   and 9 nonzeros.  */


#define NUMROWS   3
#define NUMCOLS    4
#define NUMNZ      9




int
main (void)
{
/* Declare pointers for the variables and arrays that will contain
   the data which define the LP problem.  The setproblemdata() routine
   allocates space for the problem data.  */


   char     *probname = NULL;
   int      numcols;
   int      numrows;
   int      objsen;
   double   *obj = NULL;
   double   *rhs = NULL;
   char     *sense = NULL;
   int      *matbeg = NULL;
   int      *matcnt = NULL;
   int      *matind = NULL;
   double   *matval = NULL;
   double   *lb = NULL;
   double   *ub = NULL;
   char     *ctype = NULL;


   /* Declare and allocate space for the variables and arrays where we will
      store the optimization results including the status, objective value,
      variable values, and row slacks. */


   int      solstat;
   double   objval;
   double   x[NUMCOLS];
   double   slack[NUMROWS];




   CPXENVptr     env = NULL;
   CPXLPptr      lp = NULL;
   int           status;
   int           i, j;
   int           cur_numrows, cur_numcols;


   /* Initialize the CPLEX environment */


   env = CPXopenCPLEX (&status);//打开一个工作环境


   /* Turn on output to the screen */


   status = CPXsetintparam (env, CPX_PARAM_SCRIND, CPX_ON);
   //This routine sets the value of a CPLEX parameter of type int.(设置整数变量的参数)
   //CPX_PARAM_SCRIND  if On --Display messages on screen...(设置是否显示在屏幕上面)
   /* Fill in the data for the problem.  */


   status = setproblemdata (&probname, &numcols, &numrows, &objsen, &obj,
                            &rhs, &sense, &matbeg, &matcnt, &matind, &matval,
                            &lb, &ub, &ctype);
   //(对数据设置具体的数值)
   /* Create the problem. */


   lp = CPXcreateprob (env, &status, probname);
   /*(创建一个对象)
     The routine CPXcreateprob() creates a CPLEX problem object in the CPLEX environment. The arguments to CPXcreateprob() define an LP problem name. 
     The problem that is created is an LP minimization problem with zero constraints, zero variables, and an empty constraint matrix. 
The CPLEX problem object exists until the routine CPXfreeprob() is called.
(用于创建一个问题对象,但是目前是空的,零约束,零变量,空约束矩阵)
     To define the constraints, variables, and nonzero entries of the constraint matrix, any of the CPLEX LP problem modification routines may be used. 
In addition, any of the routines beginning with the prefix CPXcopy may be used to copy data into the CPLEX problem object. 
New constraints or new variables can be created with the routines CPXnewrows() or CPXnewcols(), respectively.
(要定义约束或者矩阵,需要用到CPXnewrows()等函数)
   */
   /* Now copy the problem data into the lp */


   status = CPXcopylp (env, lp, numcols, numrows, objsen, obj, rhs,
                       sense, matbeg, matcnt, matind, matval,
                       lb, ub, NULL);
   /*
   Description
   (复制与约束,目标函数相关的内容)
   The routine CPXcopylp() copies data that defines an LP problem to a CPLEX LP problem object. 
   The arguments to CPXcopylp() define an objective function, the constraint matrix, the right-hand side, and the bounds on the variables.
   The CPXcopylp() routine does not copy names. Calling CPXcopylp() destroys any existing data associated with the LP problem object.
   The more comprehensive routine CPXcopylpwnames() can be used in place of CPXcopylp() to copy linear programs with associated names.


   The arguments passed to CPXcopylp() define a linear program. Note that these arguments are copied into local arrays maintained by CPLEX. 
   Hence, the LP problem data passed via CPXcopylp() may be modified or freed after the call to CPXcopylp() without affecting the state of the LP problem object.
   
   Synopsis


   int CPXcopylp (CPXENVptr env,(cplex 环境)
  CPXLPptr lp,(line problem 对象)
  int numcols,(column 数目)
  int numrows,(rows  数目)
  int objsen,(目标最大最小化  1 最小,-1 最大)
  double *obj,(目标函数的系数)
  double *rhs,(约束条件右边项)
  char *sense,(表示不等式的大于  小于 等于 等标识)
  int *matbeg,(一下4个参数用于表示约束矩阵)
  int *matcnt,
  int *matind,
  double *matval,
  double *lb,(上下限)
  double *ub,
  double *rngval
  );
Example


 status = CPXcopylp (env, lp, numcols, numrows, objsen, obj, rhs,
                    sense, matbeg, matcnt, matind, matval, lb,
                    ub, rngval);
   */
   /* Now copy the ctype array */


   status = CPXcopyctype (env, lp, ctype);
   //(复制变量类型)
   /* Optimize the problem and obtain solution. */


   status = CPXmipopt (env, lp);
  /*
  (求解问题)
  At any time after a mixed integer program has been created via a call to CPXcreateprob(), the routine CPXmipopt() may be used to find a solution to that problem.
  */


   solstat = CPXgetstat (env, lp);
   /*
   (用于求解结果值)
   The routine CPXgetstat() is used to access the solution status of the problem after an LP, QP, or mixed integer optimization.
   */
   
   /* Write the output to the screen. */


   printf ("\nSolution status = %d\n", solstat);


   status = CPXgetobjval (env, lp, &objval);
   /*
   (用于返回目标函数值)
   The routine CPXgetobjval() is used to return the LP or QP solution objective value.
   */
   if ( status ) {
      fprintf (stderr,"No MIP objective value available.  Exiting...\n");
      goto TERMINATE;
   }
   
   printf ("Solution value  = %f\n\n", objval);


   /* The size of the problem should be obtained by asking CPLEX what
      the actual size is, rather than using what was passed to CPXcopylp.
      cur_numrows and cur_numcols store the current number of rows and
      columns, respectively.  */


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


   status = CPXgetx (env, lp, x, 0, cur_numcols-1);
   /*(获取结果值)
   The routine CPXgetx() is used to access the solution values for a range of problem variables of a linear 
    or quadratic program. The beginning and end of the range must be specified.
   */
   if ( status ) {
      fprintf (stderr, "Failed to get optimal integer x.\n");
      goto TERMINATE;
   }


   status = CPXgetslack (env, lp, slack, 0, cur_numrows-1);
   if ( status ) {
      fprintf (stderr, "Failed to get optimal slack values.\n");
      goto TERMINATE;
   }


   for (i = 0; i < cur_numrows; i++) {
      printf ("Row %d:  Slack = %10f\n", i, slack[i]);
   }


   for (j = 0; j < cur_numcols; j++) {
      printf ("Column %d:  Value = %10f\n", j, x[j]);
   }


   /* Finally, write a copy of the problem to a file. */


   status = CPXwriteprob (env, lp, "mipex1.lp", NULL);
   if ( status ) {
      fprintf (stderr, "Failed to write LP to disk.\n");
      goto TERMINATE;
   }




TERMINATE:


   /* Free up the problem as allocated by CPXcreateprob, 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[CPXMESSAGEBUFSIZE];
         fprintf (stderr, "Could not close CPLEX environment.\n");
         CPXgeterrorstring (env, status, errmsg);
         fprintf (stderr, "%s", errmsg);
      }
   }


   /* Free up the problem data arrays, if necessary. */


   free_and_null ((char **) &probname);
   free_and_null ((char **) &obj);
   free_and_null ((char **) &rhs);
   free_and_null ((char **) &sense);
   free_and_null ((char **) &matbeg);
   free_and_null ((char **) &matcnt);
   free_and_null ((char **) &matind);
   free_and_null ((char **) &matval);
   free_and_null ((char **) &lb);
   free_and_null ((char **) &ub);
   free_and_null ((char **) &ctype);


   return (status);


}  /* END main */




/* This function fills in the data structures for the mixed integer program:


      Maximize
       obj: x1 + 2 x2 + 3 x3 + x4
      Subject To
       c1: - x1 + x2 + x3 + 10x4  <= 20
       c2: x1 - 3 x2 + x3         <= 30
       c3:       x2       - 3.5x4  = 0
      Bounds
       0 <= x1 <= 40
       2 <= x4 <= 3
      Integers
        x4
      End
 */




static int
setproblemdata (char **probname_p, int *numcols_p, int *numrows_p,
                int *objsen_p, double **obj_p, double **rhs_p,
                char **sense_p, int **matbeg_p, int **matcnt_p,
                int **matind_p, double **matval_p,
                double **lb_p, double **ub_p, char **ctype_p)
{
   char     *zprobname = NULL;     /* Problem name <= 16 characters */  
   double   *zobj = NULL;
   double   *zrhs = NULL;
   char     *zsense = NULL;
   int      *zmatbeg = NULL;
   int      *zmatcnt = NULL;
   int      *zmatind = NULL;
   double   *zmatval = NULL;
   double   *zlb = NULL;
   double   *zub = NULL;
   char     *zctype = NULL;
   int      status = 0;
   
   //Malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。
   zprobname = (char *) malloc (16 * sizeof(char));
   zobj      = (double *) malloc (NUMCOLS * sizeof(double));
   zrhs      = (double *) malloc (NUMROWS * sizeof(double));
   zsense    = (char *) malloc (NUMROWS * sizeof(char));
   zmatbeg   = (int *) malloc (NUMCOLS * sizeof(int));
   zmatcnt   = (int *) malloc (NUMCOLS * sizeof(int));
   zmatind   = (int *) malloc (NUMNZ * sizeof(int));
   zmatval   = (double *) malloc (NUMNZ * sizeof(double));
   zlb       = (double *) malloc (NUMCOLS * sizeof(double));//变量的上下限,多少个变量n 就N*sizeof()
   zub       = (double *) malloc (NUMCOLS * sizeof(double));
   zctype    = (char *) malloc (NUMCOLS * sizeof(char));//类型


   if ( zprobname == NULL || zobj    == NULL ||
        zrhs      == NULL || zsense  == NULL ||
        zmatbeg   == NULL || zmatcnt == NULL ||
        zmatind   == NULL || zmatval == NULL ||
        zlb       == NULL || zub     == NULL ||
        zctype    == NULL                       )  {
      status = 1;
      goto TERMINATE;
   }


   strcpy (zprobname, "example");


   /* The code is formatted to make a visual correspondence
      between the mathematical linear program and the specific data
      items.   */


     //目标函数系数
      zobj[0]  = 1.0;   zobj[1]   = 2.0;  zobj[2]    = 3.0;    zobj[3] = 1.0;  


/*这儿4个数组,只需要存储不为零的个数
 zmatbeg[]表示每列数据开始在zmatval中的位置
 zmatcnt[]统计每列的个数
 zmatind[]数组行位置
 zmatval[]数据
 */
 zmatbeg[0] = 0;    zmatbeg[1] = 2;    zmatbeg[2] = 5;   zmatbeg[3] = 7;
 zmatcnt[0] = 2;    zmatcnt[1] = 3;    zmatcnt[2] = 2;   zmatcnt[3] = 2;


 zmatind[0] = 0;    zmatind[2] = 0;    zmatind[5] = 0;   zmatind[7] = 0;
 zmatval[0] = -1.0; zmatval[2] = 1.0;  zmatval[5] = 1.0; zmatval[7] = 10.0;


 zmatind[1] = 1;    zmatind[3] = 1;    zmatind[6] = 1;     
 zmatval[1] = 1.0;  zmatval[3] = -3.0; zmatval[6] = 1.0;   


 zmatind[4] = 2;                      zmatind[8] = 2;
 zmatval[4] = 1.0;                    zmatval[8] = -3.5;
    //问题的上下限值
   zlb[0] = 0.0;   zlb[1] = 0.0;      zlb[2] = 0.0;     zlb[3] = 2.0;
   zub[0] = 40.0;  zub[1] = CPX_INFBOUND; zub[2] = CPX_INFBOUND; zub[3] = 3.0;
    //问题的变量类型,'C'表示连续变量;'I' 表示整数变量
    zctype[0] = 'C';    zctype[1] = 'C';   zctype[2] = 'C';   zctype[3] = 'I';


  /* The right-hand-side values don't fit nicely on a line above.  So put
     them here.  */
//右边项的表示
   zsense[0] = 'L';
   zrhs[0]   = 20.0;


   zsense[1] = 'L';
   zrhs[1]   = 30.0;


   zsense[2] = 'E';
   zrhs[2]   = 0.0;




TERMINATE:


   if ( status ) {
      free_and_null ((char **) &zprobname);
      free_and_null ((char **) &zobj);
      free_and_null ((char **) &zrhs);
      free_and_null ((char **) &zsense);
      free_and_null ((char **) &zmatbeg);
      free_and_null ((char **) &zmatcnt);
      free_and_null ((char **) &zmatind);
      free_and_null ((char **) &zmatval);
      free_and_null ((char **) &zlb);
      free_and_null ((char **) &zub);
      free_and_null ((char **) &zctype);
   }
   else {
      *numcols_p   = NUMCOLS;
      *numrows_p   = NUMROWS;
      *objsen_p    = CPX_MAX;   /* The problem is maximization */


      *probname_p  = zprobname;
      *obj_p       = zobj;
      *rhs_p       = zrhs;
      *sense_p     = zsense;
      *matbeg_p    = zmatbeg;
      *matcnt_p    = zmatcnt;
      *matind_p    = zmatind;
      *matval_p    = zmatval;
      *lb_p        = zlb;
      *ub_p        = zub;
      *ctype_p     = zctype;
   }
   return (status);


}  /* END setproblemdata */






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


static void
free_and_null (char **ptr)
{
   if ( *ptr != NULL ) {
      free (*ptr);
      *ptr = NULL;
   }
} /* END free_and_null */


你可能感兴趣的:(Tools)