/*********************************************************************** 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 #include #include #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; 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; /* 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); }