/***********************************************************************
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[]="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=XPRSmipoptimize(probg,"")) errormsg("XPRSmipoptimize",__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=XPRSgetmipsol(probg,x,NULL)) errormsg("XPRSgetmipsol",__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);
}
|