Initializing help system before first use

Modify problem: add an extra variable within an additional constraint


Type: Cutting stock
Rating: 3 (intermediate)
Description: We take the trimloss problem described in trimloss.mat, in which each integer variable x(p) represents the number of rolls cut to pattern p. We define a new integer variable y=SUM(p)x(p) and add the associated constraint We do this by first adding a row containing the (unitary) coefficients of the x(p), and then a column corresponding to y. We output the revised matrix to a file and then solve the revised MIP, giving y the highest branching priority. Finally, we output the solution, both to the screen and to an ASCII solution file.
File(s): trimloss.c
Data file(s): trimloss.mat


trimloss.c
/***********************************************************************
   Xpress Optimizer Examples
   =========================

   file trimloss.c
   ```````````````
   Modify a problem by adding an extra variable within an additional 
   constraint.    

   We take a trimloss problem in which each integer variable x(p)  
   represents the number of rolls cut to pattern p.
   We define a new integer variable y=SUM(p)x(p) and add the associated
   constraint 
                           x(1)+x(2)+...+x(N)-y = 0     
   We do this by first adding a row containing the (unitary)      
   coefficients of the x(p), and then a column corresponding to y.  
   We output the revised matrix to a file and then solve the revised  
   MIP, giving y the highest branching priority. Finally, we output  
   the solution, both to the screen and to an ASCII solution file.   

   (c) 2017 Fair Isaac Corporation       
***********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xprs.h"                 /* Optimizer header file */

XPRSprob probg;

void XPRS_CC optimizermsg(XPRSprob prob, void* data, const char *sMsg,int nLen,int nMsgLvl);
void errormsg(const char *sSubName,int nLineNo,int nErrCode);

int main()
{
   int    nReturn;                        /* Return value of Optimizer subroutine */
   int    nOptimizerVersion;              /* Optimizer version number */
   char   sProblem[]="..\\data\\trimloss";/* Problem name */
   char   sLogFile[]="trimloss.log";      /* Log file name */

   int    nRow;            /* Number of rows */
   int    nCol;            /* Number of columns */
   int    i;               /* Loop counter */

   /* New row variables */
   int    nNewRow = 1;     /* Number of new rows */
   int    nRowElem;        /* Number of non-zero elements in the new row */
   double *pRowVal;        /* Values of the new row elements */
   int    *pColInd;        /* Column indices of the new row elements */
   int    nRowStart[1];    /* Start position of the row in pRowVal */
   char   sRowType[1];     /* New row type */
   double dRHS[1];         /* New RHS value */
   char   sRowName[9];     /* New row name */

   /* New column variables */
   int    nNewCol = 1;     /* Number of new columns */
   int    nColElem;        /* Number of non-zero elements in the new column */
   double *pColVal;        /* Values of the new column elements */
   int    *pRowInd;        /* Row indices of the new column elements */
   int    nColStart[1];    /* Start position of the column in pColVal */
   double dObjCoef[1];     /* Objective coefficient of the new column */
   double dUpperBnd[1];    /* Upper bound on the new column */
   double dLowerBnd[1];    /* Lower bound on the new column */
   char   sColType[1];     /* New column type */
   int    nNewColInd[1];   /* New column index */
   int    nTypeChg = 1;    /* Number of column types to change - to make y
                              an integer variable */
   char   sColName[9];     /* New column name */
   int    nColPrior[1];    /* Branching priority of the new column */
   int    nExpiry;
   char   cOptMessage[200];
   int istudent;

   /* Solution variables */
   double dObjVal;         /* Objective value of the best integer solution found */
   double *x;              /* Primal solution values */

   char banner[256];

   /* Initialise Optimizer */
   nReturn=XPRSinit(NULL);
   XPRSgetbanner(banner); printf("%s",banner);
   if (nReturn == 8) return(1);
   istudent = (nReturn == 32); /* Check for student license */

   nReturn=XPRScreateprob(&probg);
   if (nReturn != 0 && nReturn != 32) errormsg("XPRScreateprob",__LINE__,nReturn);

   /* Remove and define log file */
   remove(sLogFile);
   if (nReturn=XPRSsetlogfile(probg,sLogFile)) errormsg("XPRSsetlogfile",__LINE__,nReturn);

   /* Tell Optimizer to call optimizermsg whenever a message is output */
   nReturn=XPRSsetcbmessage(probg,optimizermsg,NULL);

   /* Get and display the Optimizer version number */
   if (nReturn=XPRSgetintcontrol(probg,XPRS_VERSION,&nOptimizerVersion)) errormsg("XPRSgetintcontrol",__LINE__,nReturn);
   printf("Xpress Optimiser Subroutine Library Release %.2f\n\n",
      (float)nOptimizerVersion/100);

   /* Turn off presolve and permit no cuts */
   if (nReturn=XPRSsetintcontrol(probg,XPRS_PRESOLVE,0)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);
   if (nReturn=XPRSsetintcontrol(probg,XPRS_CUTSTRATEGY,0)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);

   /* Read the problem file */
   if (nReturn=XPRSreadprob(probg,sProblem,"")) errormsg("XPRSreadprob",__LINE__,nReturn);

   /* Get the number of rows and columns */
   if (nReturn=XPRSgetintattrib(probg,XPRS_ROWS,&nRow)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);
   if (nReturn=XPRSgetintattrib(probg,XPRS_COLS,&nCol)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);

   /*** Construct and add the new row ***/

   /* Assign the number of new row elements*/
   nRowElem = nCol;

   /* Allocate memory for the new row arrays */
   pRowVal=malloc(nRowElem * sizeof(double));
   pColInd=malloc(nRowElem * sizeof(int));
   if (!pRowVal || !pColInd ) errormsg("malloc",__LINE__,-1);

   /* Construct the new row */
   dRHS[0]       = 0.0;
   nRowStart[0]  = 0;
   sRowType[0]   = 'E';
   /* Store the coefficents of the x(p) */
   for (i = 0; i < nCol; i++) {
      pRowVal[i] = 1.0;
      pColInd[i] = i;
   }

   /* Add the new row */
   if (nReturn=XPRSaddrows(probg,nNewRow,nRowElem,sRowType,dRHS,NULL,nRowStart,pColInd,
       pRowVal)) errormsg("XPRSaddrows",__LINE__,nReturn);

   /* Update the number of rows */
   if (nReturn=XPRSgetintattrib(probg,XPRS_ROWS,&nRow)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);

   /* Add new row name */
   strcpy(sRowName,"NewRow");
   if (nReturn=XPRSaddnames(probg,1,sRowName,nRow-1,nRow-1))
       errormsg("XPRSaddnames",__LINE__,nReturn);

   /*** Construct and add the new column ***/

   /* Assign the number of new column elements*/
   nColElem = 1;

   /* Allocate memory for the new column arrays */
   pColVal=malloc(nColElem  * sizeof(double));
   pRowInd=malloc(nColElem  * sizeof(int));
   if (!pColVal || !pRowInd) errormsg("malloc",__LINE__,-1);

   /* Construct the new column */
   dObjCoef[0]  = 0.0;
   nColStart[0] = 0;
   pColVal[0]   = -1.0; /* the coefficent of -y */
   pRowInd[0]   = nRow-1;
   dLowerBnd[0] = 0.0;
   dUpperBnd[0] = 90;   /* the sum of the bounds on the x(p) */

   /* Add the new column */
   if (nReturn=XPRSaddcols(probg,nNewCol,nColElem,dObjCoef,nColStart,pRowInd,pColVal,
       dLowerBnd,dUpperBnd)) errormsg("XPRSaddcols",__LINE__,nReturn);

   /* Update the number of columns */
   if (nReturn=XPRSgetintattrib(probg,XPRS_COLS,&nCol)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);

   /* Make the new column an integer variable */
   nTypeChg=1;
   nNewColInd[0]=nCol-1;
   sColType[0]= 'I';

   if (nReturn=XPRSchgcoltype(probg,nTypeChg,nNewColInd,sColType))
       errormsg("XPRSchgcoltype",__LINE__,nReturn);

   /* Add new column name */
   strcpy(sColName,"y");
   if (nReturn=XPRSaddnames(probg,2,sColName,nCol-1,nCol-1))
       errormsg("XPRSaddnames",__LINE__,nReturn);

   /*** Output the revised matrix ***/
   if ( ! istudent ) {
     if (nReturn=XPRSwriteprob(probg,"revised","")) errormsg("XPRSwriteprob",__LINE__,nReturn);
   }

   /*** Solve the revised MIP ***/

   /* Assign the y variable a high branching priority (1)
      - by default the original x(p) variables have low priority (500) */
   nColPrior[0] = 1;

   /* Load this directive */
   if (nReturn=XPRSloaddirs(probg,1,nNewColInd,nColPrior,NULL,NULL,NULL))
      errormsg("XPRSloaddirs",__LINE__,nReturn);

   /* Solve the MIP */
   printf("Solving problem %s:\n\n",sProblem);
   if (nReturn=XPRSminim(probg,"g")) errormsg("XPRSminim",__LINE__,nReturn);

   /* Get the objective value of the best integer solution found */
   if (nReturn=XPRSgetdblattrib(probg,XPRS_MIPOBJVAL,&dObjVal)) errormsg("XPRSgetdblattrib",__LINE__,nReturn);

   /* Allocate memory to the solution array */
   x=malloc(nCol*sizeof(double));
   if (!x) errormsg("malloc",__LINE__,-1);

   /* Get the primal solution values */
   if (nReturn=XPRSgetsol(probg,x,NULL,NULL,NULL)) errormsg("XPRSgetsol",__LINE__,nReturn);

   /* Display the objective and solution values */
   printf("   Minimum loss is %g\n\n",dObjVal);
   printf("   The solution values are\n");
   for(i = 0; i < nCol-1; i++)
      printf("        x(%d)=%g\n",i+1,x[i]);
   printf("        y = %g\n\n",x[nCol-1]);

   /* Save the solution to an ASCII file */
   if ( ! istudent ) {
     if (nReturn=XPRSwritesol(probg,"revised","")) errormsg("XPRSwritesol",__LINE__,nReturn);
   }

   /* Free memory and close files */
   free(pRowVal);
   free(pColInd);
   free(pColVal);
   free(pRowInd);
   free(x);
   if (nReturn=XPRSdestroyprob(probg)) errormsg("XPRSdestroyprob",__LINE__,nReturn);
   if (nReturn=XPRSfree()) errormsg("XPRSfree",__LINE__,nReturn);

   return 0;
   }


/**********************************************************************************\
* Name:         optimizermsg                                                          *
* Purpose:      To display Optimizer error messages and warnings.                       *
* Arguments:    const char *sMsg       Message string                              *
*               int nLen               Message length                              *
*               int nMsgLvl            Message type                                *
\**********************************************************************************/
void XPRS_CC optimizermsg(XPRSprob prob,void* data,const char *sMsg,int nLen,int nMsgLvl)
{
   switch (nMsgLvl) {

      /* Print Optimizer error messages and warnings */
      case 4:       /* error */
      case 3:       /* warning */
         printf("%*s\n",nLen,sMsg);
         break;

      /* Ignore other messages */
      case 2:       /* dialogue */
      case 1:       /* information */
         break;

      /* Exit and flush buffers */
      default:
         fflush(NULL);
         break;
    }
}


/**********************************************************************************\
* Name:         errormsg                                                           *
* Purpose:      To display error information about failed subroutines.             *
* Arguments:    const char *sSubName   Subroutine name                             *
*               int nLineNo            Line number                                 *
*               int nErrCode           Error code                                  *
* Return Value: None                                                               *
\**********************************************************************************/
void errormsg(const char *sSubName,int nLineNo,int nErrCode)
{
   int nErrNo;             /* Optimizer error number */

   /* Print error message */
   printf("The subroutine %s has failed on line %d\n",sSubName,nLineNo);

   /* Append the error code, if it exists */
   if (nErrCode!=-1) printf("with error code %d\n",nErrCode);

   /* Append Optimizer error number,if available */
   if (nErrCode==32) {
      XPRSgetintattrib(probg,XPRS_ERRORCODE,&nErrNo);
      printf("The Optimizer error number is: %d\n",nErrNo);
   }

   /* Free memory,close files and exit */
   XPRSdestroyprob(probg);
   XPRSfree();
   exit(nErrCode);
}