Beispiel #1
0
int
main (void)
{
   int status;
   CPXENVptr env;
   CPXLPptr lp;
   CPXDIM i;
   double x[NUMCOLS];
   double cpi[NUMCOLS];
   double rpi[NUMROWS];
   double qpi[NUMQS];
   double slack[NUMROWS], qslack[NUMQS];
   double kktsum[NUMCOLS];

   /* ********************************************************************** *
    *                                                                        *
    *    S E T U P   P R O B L E M                                           *
    *                                                                        *
    * ********************************************************************** */

   /* Create CPLEX environment and enable screen output.
    */
   env = CPXXopenCPLEX (&status);
   if ( status != 0 )
      goto TERMINATE;
   status = CPXXsetintparam (env, CPXPARAM_ScreenOutput, CPX_ON);
   if ( status != 0 )
      goto TERMINATE;

   /* Create the problem object and populate it.
    */
   lp = CPXXcreateprob (env, &status, "qcpdual");
   if ( status != 0 )
      goto TERMINATE;
   status = CPXXnewcols (env, lp, NUMCOLS, obj, lb, ub, NULL, cname);
   if ( status != 0 )
      goto TERMINATE;
   status = CPXXaddrows (env, lp, 0, NUMROWS, NUMNZS, rhs, sense,
                         rmatbeg, rmatind, rmatval, NULL, rname);
   if ( status != 0 )
      goto TERMINATE;
   for (i = 0; i < NUMQS; ++i) {
      CPXNNZ const linend = (i == NUMQS - 1) ? NUMLINNZ : linbeg[i + 1];
      CPXNNZ const quadend = (i == NUMQS - 1) ? NUMQUADNZ : quadbeg[i + 1];

      status = CPXXaddqconstr (env, lp, linend - linbeg[i],
                               quadend - quadbeg[i], qrhs[i], qsense[i],
                               &linind[linbeg[i]], &linval[linbeg[i]],
                               &quadrow[quadbeg[i]], &quadcol[quadbeg[i]],
                               &quadval[quadbeg[i]], qname[i]);
      if ( status != 0 )
         goto TERMINATE;
   }

   /* ********************************************************************** *
    *                                                                        *
    *    O P T I M I Z E   P R O B L E M                                     *
    *                                                                        *
    * ********************************************************************** */
   status = CPXXsetdblparam (env, CPXPARAM_Barrier_QCPConvergeTol, 1e-10);
   if ( status != 0 )
      goto TERMINATE;

   /* Solve the problem.
    */
   status = CPXXbaropt (env, lp);
   if ( status != 0 )
      goto TERMINATE;

   if ( CPXXgetstat (env, lp) != CPX_STAT_OPTIMAL ) {
      fprintf (stderr, "No optimal solution found!\n");
      goto TERMINATE;
   }

   /* ********************************************************************** *
    *                                                                        *
    *    Q U E R Y   S O L U T I O N                                         *
    *                                                                        *
    * ********************************************************************** */

   /* Optimal solution and slacks for linear and quadratic constraints. */
   status = CPXXgetx (env, lp, x, 0, NUMCOLS - 1);
   if ( status != 0 )
      goto TERMINATE;
   status = CPXXgetslack (env, lp, slack, 0, NUMROWS - 1);
   if ( status != 0 )
      goto TERMINATE;
   status = CPXXgetqconstrslack (env, lp, qslack, 0, NUMQS - 1);
   if ( status != 0 )
      goto TERMINATE;
   /* Dual multipliers for linear constraints and bound constraints. */
   status = CPXXgetdj (env, lp, cpi, 0, NUMCOLS - 1);
   if ( status != 0 )
      goto TERMINATE;
   status = CPXXgetpi (env, lp, rpi, 0, NUMROWS - 1);
   if ( status != 0 )
      goto TERMINATE;
   status = getqconstrmultipliers (env, lp, x, qpi, ZEROTOL);
   if ( status != 0 )
      goto TERMINATE;

   /* ********************************************************************** *
    *                                                                        *
    *    C H E C K   K K T   C O N D I T I O N S                             *
    *                                                                        *
    *    Here we verify that the optimal solution computed by CPLEX (and     *
    *    the qpi[] values computed above) satisfy the KKT conditions.        *
    *                                                                        *
    * ********************************************************************** */

   /* Primal feasibility: This example is about duals so we skip this test. */

   /* Dual feasibility: We must verify
    * - for <= constraints (linear or quadratic) the dual
    *   multiplier is non-positive.
    * - for >= constraints (linear or quadratic) the dual
    *   multiplier is non-negative.
    */
   for (i = 0; i < NUMROWS; ++i) {
      switch (sense[i]) {
      case 'E': /* nothing */ break;
      case 'R': /* nothing */ break;
      case 'L':
         if ( rpi[i] > ZEROTOL ) {
            fprintf (stderr,
                     "Dual feasibility test failed for <= row %d: %f\n",
                     i, rpi[i]);
            status = -1;
            goto TERMINATE;
         }
         break;
      case 'G':
         if ( rpi[i] < -ZEROTOL ) {
            fprintf (stderr,
                     "Dual feasibility test failed for >= row %d: %f\n",
                     i, rpi[i]);
            status = -1;
            goto TERMINATE;
         }
         break;
      }
   }
   for (i = 0; i < NUMQS; ++i) {
      switch (qsense[i]) {
      case 'E': /* nothing */ break;
      case 'L':
         if ( qpi[i] > ZEROTOL ) {
            fprintf (stderr,
                     "Dual feasibility test failed for <= quad %d: %f\n",
                     i, qpi[i]);
            status = -1;
            goto TERMINATE;
         }
         break;
      case 'G':
         if ( qpi[i] < -ZEROTOL ) {
            fprintf (stderr,
                     "Dual feasibility test failed for >= quad %d: %f\n",
                     i, qpi[i]);
            status = -1;
            goto TERMINATE;
         }
         break;
      }
   }

   /* Complementary slackness.
    * For any constraint the product of primal slack and dual multiplier
    * must be 0.
    */
   for (i = 0; i < NUMROWS; ++i) {
      if ( sense[i] != 'E' && fabs (slack[i] * rpi[i]) > ZEROTOL ) {
         fprintf (stderr,
                  "Complementary slackness test failed for row %d: %f\n",
                  i, fabs (slack[i] * rpi[i]));
         status = -1;
         goto TERMINATE;
      }
   }
   for (i = 0; i < NUMQS; ++i) {
      if ( qsense[i] != 'E' && fabs (qslack[i] * qpi[i]) > ZEROTOL ) {
         fprintf (stderr,
                  "Complementary slackness test failed for quad %d: %f\n",
                  i, fabs (qslack[i] * qpi[i]));
         status = -1;
         goto TERMINATE;
      }
   }
   for (i = 0; i < NUMCOLS; ++i) {
      if ( ub[i] < CPX_INFBOUND ) {
         double const slk = ub[i] - x[i];
         double const dual = cpi[i] < -ZEROTOL ? cpi[i] : 0.0;
         if ( fabs (slk * dual) > ZEROTOL ) {
            fprintf (stderr,
                     "Complementary slackness test failed for ub %d: %f\n",
                     i, fabs (slk * dual));
            status = -1;
            goto TERMINATE;
         }
      }
      if ( lb[i] > -CPX_INFBOUND ) {
         double const slk = x[i] - lb[i];
         double const dual = cpi[i] > ZEROTOL ? cpi[i] : 0.0;
         if ( fabs (slk * dual) > ZEROTOL ) {
            printf ("lb=%f, x=%f, cpi=%f\n", lb[i], x[i], cpi[i]);
            fprintf (stderr,
                     "Complementary slackness test failed for lb %d: %f\n",
                     i, fabs (slk * dual));
            status = -1;
            goto TERMINATE;
         }
      }
   }

   /* Stationarity.
    * The difference between objective function and gradient at optimal
    * solution multiplied by dual multipliers must be 0, i.e., for the
    * optimal solution x
    * 0 == c
    *      - sum(r in rows)  r'(x)*rpi[r]
    *      - sum(q in quads) q'(x)*qpi[q]
    *      - sum(c in cols)  b'(x)*cpi[c]
    * where r' and q' are the derivatives of a row or quadratic constraint,
    * x is the optimal solution and rpi[r] and qpi[q] are the dual
    * multipliers for row r and quadratic constraint q.
    * b' is the derivative of a bound constraint and cpi[c] the dual bound
    * multiplier for column c.
    */

   /* Objective function. */
   for (i = 0; i < NUMCOLS; ++i)
      kktsum[i] = obj[i];

   /* Linear constraints.
    * The derivative of a linear constraint ax - b (<)= 0 is just a.
    */
   for (i = 0; i < NUMROWS; ++i) {
      CPXNNZ const end = (i == NUMROWS - 1) ? NUMNZS : rmatbeg[i + 1];
      CPXNNZ k;

      for (k = rmatbeg[i]; k < end; ++k)
         kktsum[rmatind[k]] -= rpi[i] * rmatval[k];
   }

   /* Quadratic constraints.
    * The derivative of a constraint xQx + ax - b <= 0 is
    * Qx + Q'x + a.
    */
   for (i = 0; i < NUMQS; ++i) {
      CPXDIM j;
      CPXNNZ k;

      for (j = linbeg[i]; j < linbeg[i] + linnzcnt[i]; ++j)
         kktsum[linind[j]] -= qpi[i] * linval[j];
      for (k = quadbeg[i]; k < quadbeg[i] + quadnzcnt[i]; ++k) {
         kktsum[quadrow[k]] -= qpi[i] * x[quadcol[k]] * quadval[k];
         kktsum[quadcol[k]] -= qpi[i] * x[quadrow[k]] * quadval[k];
      }
   }

   /* Bounds.
    * The derivative for lower bounds is -1 and that for upper bounds
    * is 1.
    * CPLEX already returns dj with the appropriate sign so there is
    * no need to distinguish between different bound types here.
    */
   for (i = 0; i < NUMCOLS; ++i) {
      kktsum[i] -= cpi[i];
   }

   for (i = 0; i < NUMCOLS; ++i) {
      if ( fabs (kktsum[i]) > ZEROTOL ) {
         fprintf (stderr, "Stationarity test failed at index %d: %f\n",
                  i, kktsum[i]);
         status = -1;
         goto TERMINATE;
      }
   }

   /* KKT conditions satisfied. Dump out the optimal solutions and
    * the dual values.
    */
   printf ("Optimal solution satisfies KKT conditions.\n");
   printf ("  x[] =");
   for (i = 0; i < NUMCOLS; ++i)
      printf (" %7.3f", x[i]);
   printf ("\n");
   printf ("cpi[] =");
   for (i = 0; i < NUMCOLS; ++i)
      printf (" %7.3f", cpi[i]);
   printf ("\n");
   printf ("rpi[] =");
   for (i = 0; i < NUMROWS; ++i)
      printf (" %7.3f", rpi[i]);
   printf ("\n");
   printf ("qpi[] =");
   for (i = 0; i < NUMQS; ++i)
      printf (" %7.3f", qpi[i]);
   printf ("\n");
   
 TERMINATE:
   /* ********************************************************************** *
    *                                                                        *
    *    C L E A N U P                                                       *
    *                                                                        *
    * ********************************************************************** */

   status = CPXXfreeprob (env, &lp);
   if ( status != 0 ) {
      fprintf (stderr, "WARNING: Failed to free problem: %d\n", status);
   }
   status = CPXXcloseCPLEX (&env);
   if ( status != 0 ) {
      fprintf (stderr, "WARNING: Failed to close CPLEX: %d\n", status);
   }

   return status;
}
Beispiel #2
0
static int
create_master_ILP   (CPXENVptr env, CPXLPptr lp, double **arc_cost, 
                     CPXDIM num_nodes)
{
   CPXDIM i, j;
   int status = 0;
  
   char sense;
   char const *colname = NULL;
   CPXNNZ nzcnt, rmatbeg;
   CPXDIM *rmatind = NULL;
   double rhs, *rmatval = NULL;
   
   
   /* Change problem type */
   
   status = CPXXchgprobtype (env, lp, CPXPROB_MILP);
   if ( status ) {
      fprintf (stderr, "Error in CPXXchgprobtype, status = %d.\n", status);
      goto TERMINATE;
   }

   /* Create arc variables x(i,j), one per time 
      For simplicity, also dummy variables x(i,i) are created.
      Those variables are fixed to 0 and do not partecipate to 
      the constraints */
   
   colname = malloc (100 * sizeof(*colname));
   if ( colname == NULL ) {
      fprintf (stderr, "No memory for colname array.\n");
      status = -1;
      goto TERMINATE;
   }
   for (i = 0; i < num_nodes; ++i) {
      for (j = 0; j < num_nodes; ++j) {
         double cost = ( i == j ? 0. : arc_cost[i][j] );
         double lb   = 0.;
         double ub   = ( i == j ? 0. : 1. );
         char type   = 'B';
         sprintf ((char *)colname, "x.%d.%d", i, j);
         status = CPXXnewcols (env, lp, 1, &cost, &lb, &ub, &type, &colname);
         if ( status ) {
            fprintf (stderr, "Error in CPXXnewcols, status = %d.\n", status);
            goto TERMINATE;
         }
      }
   }

   /* Init data structures to add degree constraints */
   
   rhs = 1.;
   sense = 'E';
   rmatbeg = 0;
   rmatind = malloc ((num_nodes-1) * sizeof (*rmatind));
   if ( rmatind == NULL ) {
      fprintf (stderr, "No memory for rmatind array.\n");
      status = -1;
      goto TERMINATE;
   }
   rmatval = malloc ((num_nodes-1) * sizeof (*rmatval));
   if ( rmatval == NULL ) {
      fprintf (stderr, "No memory for rmatval array.\n");
      status = -1;
      goto TERMINATE;
   }

   /* Add the out degree constraints, one at a time:
      forall i in V: sum((i,j) in delta+(i)) x(i,j) = 1 */

   for (i = 0; i < num_nodes; ++i) {
      nzcnt = 0;
      for (j = 0; j < num_nodes; ++j) {
         if ( i != j ) {
            rmatind[nzcnt]   = i * num_nodes + j;
            rmatval[nzcnt++] = 1.;
         }
      }
      status = CPXXaddrows (env, lp, 0, 1, num_nodes-1, &rhs, &sense,
                            &rmatbeg, rmatind, rmatval, NULL, NULL);
      if ( status ) {
         fprintf (stderr, "Error in CPXXaddrows, status = %d.\n", status);
         goto TERMINATE;
      }
   }
   
   /* Add the in degree constraints, one at a time:
      forall i in V: sum((j,i) in delta-(i)) x(j,i) = 1 */

   for (i = 0; i < num_nodes; ++i) {
      nzcnt = 0;
      for (j = 0; j < num_nodes; ++j) {
         if (i != j ) {
            rmatind[nzcnt]   = j * num_nodes + i;
            rmatval[nzcnt++] = 1.;
         }
      }
      status = CPXXaddrows (env, lp, 0, 1, num_nodes-1, &rhs, &sense,
                            &rmatbeg, rmatind, rmatval, NULL, NULL);
      if ( status ) {
         fprintf (stderr, "Error in CPXXaddrows, status = %d.\n", status);
         goto TERMINATE;
      }
   }

TERMINATE:

   free_and_null ((char **) &colname);
   free_and_null ((char **) &rmatind);
   free_and_null ((char **) &rmatval);
   
   return status;

} /* END create_master_ILP */
Beispiel #3
0
static int
init_user_cbhandle  (USER_CBHANDLE *user_cbhandle, CPXDIM num_nodes, 
                     int separate_fractional_solutions)
{
   CPXDIM i, j, k;
   int status = 0;
   
   /* Data structures to create columns and add rows */

   CPXDIM num_rows;
   CPXNNZ nzcnt;
   char *sense = NULL;
   double *rhs = NULL;
   CPXNNZ *rmatbeg = NULL;
   CPXDIM *rmatind = NULL;
   double *rmatval = NULL;
   char const *colname = NULL;

   /* Init user_cbhandle */

   user_cbhandle->separate_fractional_solutions = separate_fractional_solutions;
   user_cbhandle->num_nodes  = num_nodes;
   user_cbhandle->num_x_cols = num_nodes * num_nodes;
   user_cbhandle->num_v_cols = (num_nodes - 1) * user_cbhandle->num_x_cols;
   user_cbhandle->num_u_cols = (num_nodes - 1) * num_nodes;
   user_cbhandle->env        = NULL;
   user_cbhandle->lp         = NULL;
   user_cbhandle->x          = NULL;
   user_cbhandle->indices    = NULL;
   user_cbhandle->ray        = NULL;
   user_cbhandle->cutval     = NULL;
   user_cbhandle->cutind     = NULL;
   
   user_cbhandle->x = malloc (user_cbhandle->num_x_cols *
                              sizeof(*user_cbhandle->x));
   if ( user_cbhandle->x == NULL ) {
      fprintf (stderr, "No memory for x array.\n");
      goto TERMINATE;
   }
   user_cbhandle->indices = malloc (user_cbhandle->num_x_cols *
                                    sizeof(*user_cbhandle->indices));
   if ( user_cbhandle->indices == NULL ) {
      fprintf (stderr, "No memory for indices array.\n");
      goto TERMINATE;
   }
   user_cbhandle->ray = malloc ((user_cbhandle->num_v_cols +
                                 user_cbhandle->num_u_cols) *
                                sizeof(*user_cbhandle->ray));
   if ( user_cbhandle->ray == NULL ) {
      fprintf (stderr, "No memory for ray array.\n");
      goto TERMINATE;
   }
   user_cbhandle->cutval = malloc (user_cbhandle->num_x_cols *
                                   sizeof(*user_cbhandle->cutval));
   if ( user_cbhandle->cutval == NULL ) {
      fprintf (stderr, "No memory for cutval array.\n");
      goto TERMINATE;
   }
   user_cbhandle->cutind = malloc (user_cbhandle->num_x_cols *
                                   sizeof(*user_cbhandle->cutind));
   if ( user_cbhandle->cutind == NULL ) {
      fprintf (stderr, "No memory for cutind array.\n");
      goto TERMINATE;
   }
   
   /* Create the environment for the worker LP */

   user_cbhandle->env = CPXXopenCPLEX (&status);
   if ( user_cbhandle->env == NULL ) {
      fprintf (stderr, 
         "Could not open CPLEX environment for the worker LP: status = %d.\n", 
         status); 
      goto TERMINATE;
   }

   /* Turn off the presolve reductions */
   
   status = CPXXsetintparam (user_cbhandle->env, CPXPARAM_Preprocessing_Reduce, 0);
   if ( status ) {
      fprintf(stderr, 
         "Failed to set CPXPARAM_Preprocessing_Reduce, status = %d.\n", status);
      goto TERMINATE;
   }

   /* Create the worker LP */

   user_cbhandle->lp = CPXXcreateprob (user_cbhandle->env, &status, "atsp_worker.lp");
   if ( user_cbhandle->lp == NULL ) {
      fprintf (stderr, "Failed to create the worker LP: status = %d\n", status);
      goto TERMINATE;
   }

   /* Allocate memory for column names */

   colname = malloc (100 * sizeof(*colname));
   if ( colname == NULL ) {
      fprintf (stderr, "No memory for colname array.\n");
      status = -1;
      goto TERMINATE;
   } 
   
   /* Create variables v(k,i,j), one per time 
      For simplicity, also dummy variables v(k,i,i) are created.
      Those variables are fixed to 0 and do not partecipate to 
      the constraints */
   
   for (k = 1; k < num_nodes; ++k) {
      for (i = 0; i < num_nodes; ++i) {
         for (j = 0; j < num_nodes; ++j) {
            double ub = ( i == j ? 0. : CPX_INFBOUND );
            sprintf ((char *)colname, "v.%d.%d.%d", k, i, j);
            status = CPXXnewcols (user_cbhandle->env, user_cbhandle->lp, 1, 
                                  NULL, NULL, &ub, NULL, &colname);
            if ( status ) {
               fprintf (stderr, "Error in CPXXnewcols, status = %d.\n", status);
               goto TERMINATE;
            }
         }
      }
   }

   /* Create variables u(k,i), one per time */
   
   for (k = 1; k < num_nodes; ++k) {
      for (i = 0; i < num_nodes; ++i) {
         double obj = 0.;
         double lb = -CPX_INFBOUND;
         double ub = CPX_INFBOUND;
         sprintf ((char *)colname, "u.%d.%d", k, i);
         if ( i == 0 )
            obj = -1.;
         else if ( i == k )
            obj = 1.;
         status = CPXXnewcols (user_cbhandle->env, user_cbhandle->lp, 1, 
                               &obj, &lb, &ub, NULL, &colname); 
         if ( status ) {
            fprintf (stderr, "Error in CPXXnewcols, status = %d.\n", status);
            goto TERMINATE;
         }
      }
   }

   /* Init data structures for CPXaddrows */
   
   num_rows = user_cbhandle->num_x_cols * (num_nodes - 1);

   rhs = malloc (num_rows * sizeof (*rhs));
   if ( rhs == NULL ) {
      fprintf (stderr, "No memory for rhs array.\n");
      status = -1;
      goto TERMINATE;
   }
   sense = malloc (num_rows * sizeof (*sense));
   if ( sense == NULL ) {
      fprintf (stderr, "No memory for sense array.\n");
      status = -1;
      goto TERMINATE;
   }
   rmatbeg = malloc ( (num_rows + 1) * sizeof (*rmatbeg));
   if ( rmatbeg == NULL ) {
      fprintf (stderr, "No memory for rmatbeg array.\n");
      status = -1;
      goto TERMINATE;
   }
   rmatind = malloc (3 * num_rows * sizeof (*rmatind));
   if ( rmatind == NULL ) {
      fprintf (stderr, "No memory for rmatind array.\n");
      status = -1;
      goto TERMINATE;
   }
   rmatval = malloc (3 * num_rows * sizeof (*rmatval));
   if ( rmatval == NULL ) {
      fprintf (stderr, "No memory for rmatval array.\n");
      status = -1;
      goto TERMINATE;
   }

   /* Populate data structures for CPXaddrows and add all the constraints:
      forall k in V0, forall (i,j) in A: u(k,i) - u(k,j) <= v(k,i,j) */
   
   num_rows = 0;
   nzcnt = 0;
   for (k = 1; k < num_nodes; ++k) {
      for (i = 0; i < num_nodes; ++i) {
         for (j = 0; j < num_nodes; ++j) {
            if ( i != j ) {
               rhs[num_rows]     =  0.;
               sense[num_rows]   =  'L';
               rmatbeg[num_rows] =  nzcnt;
               rmatind[nzcnt]    =  (k-1) * user_cbhandle->num_x_cols +
                                    i * num_nodes + j;
               rmatval[nzcnt++]  = -1.;
               rmatind[nzcnt]    =  user_cbhandle->num_v_cols + 
                                    (k-1) * num_nodes + i; 
               rmatval[nzcnt++]  =  1.;
               rmatind[nzcnt]    =  user_cbhandle->num_v_cols + 
                                    (k-1) * num_nodes + j; 
               rmatval[nzcnt++]  = -1.;
               ++num_rows;
            }
         }
      }
   }
   rmatbeg[num_rows] = nzcnt; 

   status = CPXXaddrows (user_cbhandle->env, user_cbhandle->lp, 
                         0, num_rows, nzcnt, rhs, sense, 
                         rmatbeg, rmatind, rmatval, NULL, NULL);
   if ( status ) {
      fprintf (stderr, "Error in CPXXaddrows: status = %d\n", status);
      goto TERMINATE;
   }

TERMINATE:

   free_and_null ((char **) &colname); 
   free_and_null ((char **) &sense);
   free_and_null ((char **) &rhs);
   free_and_null ((char **) &rmatbeg);
   free_and_null ((char **) &rmatind);
   free_and_null ((char **) &rmatval);

   return status;

} /* END init_user_cbhandle */
Beispiel #4
0
static int
buildmodel (CPXENVptr env, CPXLPptr lp)
{

   CPXDIM colcnt = NUMVARS*NUMMONTHS*NUMPRODUCTS;

   double *obj     = NULL;
   double *lb      = NULL;
   double *ub      = NULL;
   char   *ctype   = NULL;
   CPXDIM *rmatind = NULL;
   double *rmatval = NULL;

   CPXDIM indicator;
   CPXNNZ rmatbeg[1];
   double rhs[1];
   char   sense[1];

   int    m, p;
   int    status = 0;

   status = CPXXchgobjsen (env, lp, CPX_MAX); /* Maximization problem */
   if ( status ) {
      fprintf (stderr, "Could not change objective sense.\n");
      goto TERMINATE;
   }

   rmatbeg[0] = 0;

   /* Allocate colcnt-sized arrays */

   obj     = malloc (colcnt * sizeof(*obj));
   lb      = malloc (colcnt * sizeof(*lb));
   ub      = malloc (colcnt * sizeof(*ub));
   ctype   = malloc (colcnt * sizeof(*ctype));
   rmatind = malloc (colcnt * sizeof(*rmatind));
   rmatval = malloc (colcnt * sizeof(*rmatval));

   if ( obj     == NULL ||
        lb      == NULL ||
        ub      == NULL ||
        ctype   == NULL ||
        rmatind == NULL ||
        rmatval == NULL   ) {
      fprintf (stderr, "Could not allocate colcnt arrays\n");
      status = CPXERR_NO_MEMORY;
      goto TERMINATE;
   }

   /* Create variables. For each month and each product, we have 3
      variables corresponding to the quantity used (semi-continuous),
      stored (continuous) and bought (continuous) and one binary
      variable indicating whether or not the product is used during
      this month. */

   for (m = 0; m < NUMMONTHS; m++) {
      for (p = 0; p < NUMPRODUCTS; p++) {

         /* The quantity bought is a continuous variable. It has a cost */

         obj[varindex(m, p, BUY)]    = -cost[m*NUMPRODUCTS + p];
         lb[varindex (m, p, BUY)]    = 0.0;
         ub[varindex (m, p, BUY)]    = CPX_INFBOUND;
         ctype[varindex (m, p, BUY)] = 'C';

         /* When an oil is used, the quantity must be at least 20
            tons. This is modeled as a semi-continuous variable. */

         obj[varindex (m, p, USE)]   = 0.0;
         lb[varindex (m, p, USE)]    = 20.0;
         ub[varindex (m, p, USE)]    = CPX_INFBOUND;
         ctype[varindex (m, p, USE)] = 'S';

         /* It is possible to store up to 1000 tons of each
            product. There are storage costs. */

         obj[varindex (m, p, STORE)]   = -5.0;
         lb[varindex (m, p, STORE)]    = 0.0;
         ub[varindex (m, p, STORE)]    = 1000.0;
         ctype[varindex (m, p, STORE)] = 'C';

         /* At the end, we must have exactly 500 tons of each
            product in storage. */

         if ( m == NUMMONTHS - 1 ) {
            lb[varindex (m, p, STORE)] = 500.0;
            ub[varindex (m, p, STORE)] = 500.0;
         }

         /* The variable indicating whether or not a product is
            used during a month is a binary variable. */

         obj[varindex (m, p, IS_USED)]   = 0.0;
         lb[varindex (m, p, IS_USED)]    = 0.0;
         ub[varindex (m, p, IS_USED)]    = 1.0;
         ctype[varindex (m, p, IS_USED)] = 'B';
      }
   }

   status = CPXXnewcols (env, lp, colcnt, obj, lb, ub, ctype, NULL);
   if ( status ) {
      fprintf (stderr, "Could not add new columns.\n");
      goto TERMINATE;
   }

   /* Constraints for each month */

   for (m = 0; m < NUMMONTHS; m++) {
      int totalindex;

      /* For each product, create an indicator constraint linking the
         quantity used and the binary variable indicating whether or
         not the product is used */

      for (p = 0; p < NUMPRODUCTS; p++) {
         indicator  = varindex (m, p, IS_USED);
         rmatind[0] = varindex (m, p, USE);
         rmatval[0] = 1.0;
         status = CPXXaddindconstr (env, lp, indicator, 1, 1, 0.0, 'L',
                                   rmatind, rmatval, NULL);
         if ( status ) {
            fprintf (stderr, "Could not add new indicator constraint.\n");
            goto TERMINATE;
         }
      }

      /* Not more than 200 tons of vegetable oil can be refined */

      rmatind[0] = varindex (m, VEGOIL1, USE);
      rmatind[1] = varindex (m, VEGOIL2, USE);
      rmatval[0] = 1.0;
      rmatval[1] = 1.0;
      rhs[0]     = 200.0;
      sense[0]   = 'L';
      status = CPXXaddrows (env, lp, 0, 1, 2, rhs,
                           sense, rmatbeg, rmatind, rmatval,
                           NULL, NULL);

      /* Not more than 250 tons of non-vegetable oil can be refined */

      rmatind[0] = varindex (m, OIL1, USE);
      rmatind[1] = varindex (m, OIL2, USE);
      rmatind[2] = varindex (m, OIL3, USE);
      rmatval[0] = 1.0;
      rmatval[1] = 1.0;
      rmatval[2] = 1.0;
      rhs[0]     = 250.0;
      sense[0]   = 'L';
      status = CPXXaddrows (env, lp, 0, 1, 3, rhs,
                           sense, rmatbeg, rmatind, rmatval,
                           NULL, NULL);
      if ( status ) {
         fprintf (stderr, "Could not add new rows.\n");
         goto TERMINATE;
      }

      /* Constraint on food composition */

      /* Add a variable corresponding to total quantity produced
         in a month */

      obj[0]   = 150.0;
      lb[0]    = 0.0;
      ub[0]    = CPX_INFBOUND;
      ctype[0] = 'C';

      status = CPXXnewcols (env, lp, 1, obj, lb, ub, ctype, NULL);
      if ( status ) {
         fprintf (stderr, "Could not add new columns.\n");
         goto TERMINATE;
      }
      totalindex = CPXXgetnumcols (env, lp) - 1;

      /* Total quantity = sum (quantities) */

      for (p = 0; p < NUMPRODUCTS; p++) {
         rmatind[p] = varindex (m, p, USE);
         rmatval[p] = 1.0;
      }
      rmatind[NUMPRODUCTS] = totalindex;
      rmatval[NUMPRODUCTS] = -1.0;
      rhs[0]               =  0.0;
      sense[0]             = 'E';
      status = CPXXaddrows (env, lp, 0, 1, NUMPRODUCTS + 1, rhs,
                           sense, rmatbeg, rmatind, rmatval,
                           NULL, NULL);
      if ( status ) {
         fprintf (stderr, "Could not add new rows.\n");
         goto TERMINATE;
      }

      /* Hardness constraints
          sum (quantity * hardness) >= 3 * total quantity
          sum (quantity * hardness) <= 6 * total quantity
      */

      for (p = 0; p < NUMPRODUCTS; p++) {
         rmatind[p] = varindex (m, p, USE);
         rmatval[p] = hardness[p];
      }
      rmatind[NUMPRODUCTS] = totalindex;
      rmatval[NUMPRODUCTS] = -3.0;
      rhs[0]               =  0.0;
      sense[0]             = 'G';
      status = CPXXaddrows (env, lp, 0, 1, NUMPRODUCTS + 1, rhs,
                           sense, rmatbeg, rmatind, rmatval,
                           NULL, NULL);
      if ( status ) {
         fprintf (stderr, "Could not add new rows.\n");
         goto TERMINATE;
      }

      rmatval[NUMPRODUCTS] = -6.0;
      sense[0]             = 'L';
      status = CPXXaddrows (env, lp, 0, 1, NUMPRODUCTS + 1, rhs,
                           sense, rmatbeg, rmatind, rmatval,
                           NULL, NULL);
      if ( status ) {
         fprintf (stderr, "Could not add new rows.\n");
         goto TERMINATE;
      }

      /* The food may never be made up of more than three oils */

      for (p = 0; p < NUMPRODUCTS; p++) {
         rmatind[p] = varindex (m, p, IS_USED);
         rmatval[p] = 1.0;
      }
      rhs[0]   = 3.0;
      sense[0] = 'L';
      status = CPXXaddrows (env, lp, 0, 1, NUMPRODUCTS, rhs,
                           sense, rmatbeg, rmatind, rmatval,
                           NULL, NULL);
      if ( status ) {
         fprintf (stderr, "Could not add new rows.\n");
         goto TERMINATE;
      }

      /* If product veg 1 or veg 2 is used then oil 3 must be used */

      indicator  = varindex (m, VEGOIL1, IS_USED);
      rmatind[0] = varindex (m, OIL3, USE);
      rmatval[0] = 1.0;
      status = CPXXaddindconstr (env, lp, indicator, 0, 1, 20.0, 'G',
                                rmatind, rmatval, NULL);

      indicator = varindex (m, VEGOIL2, IS_USED);
      status = CPXXaddindconstr (env, lp, indicator, 0, 1, 20.0, 'G',
                                rmatind, rmatval, NULL);

      if ( status ) {
         fprintf (stderr, "Could not add new indicator constraint.\n");
         goto TERMINATE;
      }

      /* We can store each product from one month to the next,
         starting with a stock of 500 tons */

      for (p = 0; p < NUMPRODUCTS; p++) {
         CPXNNZ n = 0;
         if ( m != 0 ) {
            rmatind[n]   = varindex (m-1, p, STORE); /* stored last month */
            rmatval[n++] = 1.0;
            rmatind[n]   = varindex (m, p, BUY);     /* bought this month */
            rmatval[n++] = 1.0;
            rmatind[n]   = varindex (m, p, USE);     /* used this month */
            rmatval[n++] = -1.0;
            rmatind[n]   = varindex (m, p, STORE);   /* stored this month */
            rmatval[n++] = -1.0;
            rhs[0]       = 0.0;
            sense[0]     = 'E';
         }
         else {
            rmatind[n]   = varindex (m, p, BUY);   /* bought this month */
            rmatval[n++] = 1.0;
            rmatind[n]   = varindex (m, p, USE);   /* used this month */
            rmatval[n++] = -1.0;
            rmatind[n]   = varindex (m, p, STORE); /* stored this month */
            rmatval[n++] = -1.0;
            rhs[0]       = -500.0;
            sense[0]     = 'E';
         }
         status = CPXXaddrows (env, lp, 0, 1, n, rhs,
                              sense, rmatbeg, rmatind, rmatval,
                              NULL, NULL);
         if ( status ) {
            fprintf (stderr, "Could not add new rows.\n");
            goto TERMINATE;
         }
      }
   }

 TERMINATE:

   free_and_null ((char **)&obj);
   free_and_null ((char **)&lb);
   free_and_null ((char **)&ub);
   free_and_null ((char **)&ctype);
   free_and_null ((char **)&rmatind);
   free_and_null ((char **)&rmatval);

   return (status);

}  /* END buildmodel */
Beispiel #5
0
/* This function creates the following model:
 *   Minimize
 *    obj: x1 + x2 + x3 + x4 + x5 + x6
 *   Subject To
 *    c1: x1 + x2      + x5      = 8
 *    c2:           x3 + x5 + x6 = 10
 *    q1: [ -x1^2 + x2^2 + x3^2 ] <= 0
 *    q2: [ -x4^2 + x5^2 ] <= 0
 *   Bounds
 *    x2 Free
 *    x3 Free
 *    x5 Free
 *   End
 * which is a second order cone program in standard form.
 * The function returns a true value on success and false on error.
 * The function also sets up *cone_p as follows:
 * (*cone_p)[j] >= 0              Column j is contained in a cone constraint
 *                                and is the cone head variable of that
 *                                constraint. The index of the respective
 *                                quadratic constraint is given by (*cone_p)[j].
 * (*cone_p)[j] = NOT_CONE_HEAD   Column j is contained in a cone constraint
 *                                but is not the cone head variable of that
 *                                constraint.
 * (*cone_p)[j] = NOT_IN_CONE     Column j is not contained in any cone
 *                                constraint.
 */
static int
createmodel (CPXENVptr env, CPXLPptr lp, CPXDIM **cone_p)
{
   /* Column data. */
   static double const obj[]        = {  1.0,  1.0,  1.0,  1.0,  1.0,  1.0 };
   static double const lb[]         = {  0.0, -INF, -INF,  0.0, -INF,  0.0 };
   static double const ub[]         = {  INF,  INF,  INF,  INF,  INF,  INF };
   static char const *const cname[] = { "x1", "x2", "x3", "x4", "x5", "x6" };

   /* Row data. */
   static double const rval[]       = { 1.0, 1.0, 1.0,    1.0, 1.0, 1.0 };
   static CPXDIM const rind[]       = {   0,   1,   4,      2,   4,   5 };
   static CPXNNZ const rbeg[]       = {   0,                3           };
   static double const rhs[]        = { 8.0,             10.0           };
   static char const sense[]        = { 'E',              'E'           };
   static char const *const rname[] = { "c1",             "c2"          };

   /* Data for second order cone constraints. */
   static double const qval[]  = { -1.0, 1.0, 1.0 }; /* Same for all Q cons. */
   static double const qrhs    = 0.0;                /* Same for all Q cons. */
   static char const qsense    = 'L';                /* Same for all Q cons. */
   static CPXDIM const qind1[] = { 0, 1, 2 };
   static CPXDIM const qind2[] = { 3, 4 };

   int status;
   int ok = 0;
   CPXDIM *cone = NULL;

   CPXCHANNELptr errc;

   /* Get the channel for printing error messages. */
   if ( (status = CPXXgetchannels (env, NULL, NULL, &errc, NULL)) != 0 )
      goto TERMINATE;

   cone = malloc ((sizeof (obj) / sizeof (obj[0])) * sizeof (*cone));
   if ( cone == NULL ) {
      CPXXmsg (errc, "Out of memory!\n");
      goto TERMINATE;
   }

   status = CPXXchgobjsen (env, lp, CPX_MIN);
   if ( status != 0 )
      goto TERMINATE;

   status = CPXXnewcols (env, lp, sizeof (obj) / sizeof (obj[0]),
                         obj, lb, ub, NULL, cname);
   if ( status != 0 )
      goto TERMINATE;

   status = CPXXaddrows (env, lp, 0, sizeof (rhs) / sizeof (rhs[0]),
                         sizeof (rval) / sizeof (rval[0]), rhs, sense,
                         rbeg, rind, rval, NULL, rname);
   if ( status != 0 )
      goto TERMINATE;

   status = CPXXaddqconstr (env, lp, 0, sizeof (qind1) / sizeof (qind1[0]),
                            qrhs, qsense, NULL, NULL,
                            qind1, qind1, qval, "q1");
   if ( status != 0 )
      goto TERMINATE;
   cone[0] = 0;
   cone[1] = NOT_CONE_HEAD;
   cone[2] = NOT_CONE_HEAD;
   status = CPXXaddqconstr (env, lp, 0, sizeof (qind2) / sizeof (qind2[0]),
                            qrhs, qsense, NULL, NULL,
                            qind2, qind2, qval, "q2");
   if ( status != 0 )
      goto TERMINATE;
   cone[3] = 1;
   cone[4] = NOT_CONE_HEAD;

   cone[5] = NOT_IN_CONE;

   ok = 1;
 TERMINATE:
   if ( !ok )
      free (cone);

   *cone_p = cone;

   return ok;
}
Beispiel #6
0
static int 
rowsteel (int numprod, int tweeks, double const *rate,
          double const *inv0, double const *avail, double const *flatmarket,
          double const *prodcost, double const *invcost,
          double const *flatrevenue, CPXENVptr env, CPXLPptr lp)
{
   double *obj      = NULL;
   double *rhs      = NULL;
   char   *sense    = NULL;

   /* Row representation of the model */
   CPXNNZ *rmatbeg  = NULL;
   CPXDIM *rmatind  = NULL;
   double *rmatval  = NULL;

   CPXCHANNELptr  cpxerror = NULL;

   int    t,p;      /* Various loop counters */
   CPXDIM j;
   CPXNNZ k;

   int  status = 0;

   printf ("Building model by row.\n");

   status = CPXXgetchannels (env, NULL, NULL, &cpxerror, NULL);
   if ( status )  goto TERMINATE;

   /* Set the objective sense to be maximize */

   status = CPXXchgobjsen (env, lp, CPX_MAX);
   if ( status ) {
      CPXXmsg (cpxerror, "Could not change objective sense. Error %d\n",
               status);
      goto TERMINATE;
   }

   /* Set up the variables for the problem.  */

   /* Now fill in the bounds and the objective.  
    * For each variable type, we allocate a vector to hold the 
    * objective coefficients for one product, and multiple time
    * periods.  Note that we allocate and free the vector for
    * each decision variable type to maintain the locality of the code.
    */

   /* First, do the Make variables in (p,t) order.  The bounds are
    * (0, infinity), while the objective for Make[p][t] is -prodcost[p]
    */

   obj = malloc (tweeks*sizeof(*obj));
   if ( obj == NULL ) {
      status = -2;
      goto TERMINATE;
   }

   for (p = 0; p < numprod; p++) {
      for (t = 0; t < tweeks; t++) {
         obj[t]    = -prodcost[p];
      }
      status = CPXXnewcols (env, lp, tweeks, obj, NULL, NULL, NULL, NULL);
      if ( status ) {
         CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n",
                 "CPXXnewcols failed to add Make variables\n",
                 p, status);
         goto TERMINATE;
      }
   }

   /* Free up the obj array. */

   free (obj);  obj = NULL;
   
   /* Now do the Inv variables in (p,t) order. The bounds are
    * (0, infinity), while the objective for Inv[p][t] is -invcost[p]
    */

   obj = malloc (tweeks*sizeof(*obj));
   if ( obj == NULL ) {
      status = -2;
      goto TERMINATE;
   }

   for (p = 0; p < numprod; p++) {
      for (t = 0; t < tweeks; t++) {
         obj[t]    = -invcost[p];
      }
      status = CPXXnewcols (env, lp, tweeks, obj, NULL, NULL, NULL, NULL);
      if ( status ) {
         CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n",
                 "CPXXnewcols failed to add Inv variables\n",
                 p, status);
         goto TERMINATE;
      }
   }

   /* Free up the obj array. */

   free (obj);  obj = NULL;
   
   /* Now do the Sell[p][t] variables in (p,t) order.  The bounds on
    * Sell[p][t] are (0, flatmarket[p*tweeks+t]), and the objective
    * coefficient is flatrevenue[p*tweeks+t].  Because of this
    * structure, we do not need to allocate a temporary objective
    * coefficient array.  
    */

   for (p = 0; p < numprod; p++) {
      status = CPXXnewcols (env, lp, tweeks, &flatrevenue[p*tweeks], 
                           NULL, &flatmarket[p*tweeks], NULL, NULL);
      if ( status ) {
         CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n",
                 "CPXXnewcols failed to add Make variables\n",
                 p, status);
         goto TERMINATE;
      }
   }

   /* Now generate the constraints.  */

   /* There are tweeks time constraints, each with numprod coefficients.
    * We allocate space for the sense values, and space to hold the matrix.
    * The rhs values are in avail, so there is no need to allocate rhs.
    */

   sense   = malloc (tweeks*sizeof(*sense));
   rmatbeg = malloc (tweeks*sizeof(*rmatbeg));
   rmatind = malloc (tweeks*numprod*sizeof(*rmatind));
   rmatval = malloc (tweeks*numprod*sizeof(*rmatval));

   if ( sense   == NULL ||
        rmatbeg == NULL ||
        rmatind == NULL ||
        rmatval == NULL   ) {
      status = -2;
      goto TERMINATE;
   }

   /* Now generate the time constraints.  The senses are all 'L'.
    * There are numprod  nonzeros in each of these constraints, 
    * with nonzero value (1/rate[p]) for variable Make[p][t]. */

   k = 0;   /* The count of the nonzeros */

   for (t = 0; t < tweeks; t++) {
      sense[t] = 'L';
      rmatbeg[t] = k;
      for (p = 0; p < numprod; p++) {
         rmatind[k] = p*tweeks + t;  /* Formula for Make variable */
         rmatval[k] = 1.0/rate[p];
         k++;
      }
   }

   status = CPXXaddrows (env, lp, 0, tweeks, k, avail, sense, 
                        rmatbeg, rmatind, rmatval, NULL, NULL);
   if ( status ) {
      CPXXmsg (cpxerror, 
              "CPXXaddrows failed to add time constraints. Error %d.\n",
              status);
      goto TERMINATE;
   }

   free (sense);   sense   = NULL;
   free (rmatbeg); rmatbeg = NULL;
   free (rmatind); rmatind = NULL;
   free (rmatval); rmatval = NULL;

   /* Allocate space for each product's balance constraints.  rhs
    * and sense are needed for each time period, and each constraint
    * balance[p,t] has 4 nonzeros. 
    */ 

   rhs     = malloc (tweeks*sizeof(*rhs));
   rmatbeg = malloc (tweeks*sizeof(*rmatbeg));
   rmatind = malloc (4*tweeks*sizeof(*rmatind));
   rmatval = malloc (4*tweeks*sizeof(*rmatval));

   if ( rhs     == NULL ||
        rmatbeg == NULL ||
        rmatind == NULL ||
        rmatval == NULL   ) {
      status = -2;
      goto TERMINATE;
   }

   /* Now generate the balance constraints.  Add rows by product.
    * The rhs values are -inv0[p] for the first time period,
    * and 0.0 otherwise.  The senses are all 'E'.
    * Handle t=0 specially.
    * Use order of variables Inv[t-1], Make, Inv[t], Sell so that
    * rmatind is in column order.
    */

   for (p = 0; p < numprod; p++) {
   
      k = 0;  /* Initialize the nonzero count for each product */

      for (t = 0; t < tweeks; t++) {
         rmatbeg[t] = k;
         if ( t > 0 ) {
            rhs[t]   = 0.0;
            j = (numprod+p)*tweeks + t-1;  /* Inv[p][t-1] index */
            rmatind[k] = j;
            rmatval[k] = 1.0;
            k++;
         }
         else {
            rhs[t] = -inv0[p];
         }
         rmatind[k] = p*tweeks + t;   /* Make[p][t] index */
         rmatval[k] = 1.0;
         k++;
         rmatind[k] = (numprod+p)*tweeks + t;  /* Inv[p][t] index */
         rmatval[k] = -1.0;
         k++;
         rmatind[k] = (2*numprod+p)*tweeks + t;  /* Sell[p][t] index */
         rmatval[k] = -1.0;
         k++;
      }
      /* Now add the rows to the problem */

      status = CPXXaddrows (env, lp, 0, tweeks, k, rhs, NULL, 
                           rmatbeg, rmatind, rmatval, NULL, NULL);
      if ( status ) {
         CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n",
                 "CPXXaddrows failed to add balance constraint\n",
                 p, status);
         goto TERMINATE;
      }
 
   }

   /* Free up arrays used to build balance constraints */

   free (rhs);     rhs   = NULL;
   free (rmatbeg); rmatbeg = NULL;  
   free (rmatind); rmatind = NULL;  
   free (rmatval); rmatval = NULL;  

TERMINATE:

   if ( rmatbeg != NULL )   free ( rmatbeg );
   if ( rmatind != NULL )   free ( rmatind );
   if ( rmatval != NULL )   free ( rmatval );
   if ( rhs     != NULL )   free ( rhs );
   if ( sense   != NULL )   free ( sense );
   if ( obj     != NULL )   free ( obj );

   return (status);

} /* END rowsteel */