/***********************************************************************
Xpress Optimizer Examples
=========================
file knapsack.c
````````````````
Apply a primal heuristic to a knapsack problem.
The program demonstrates the use of the global log callback.
We take the knapsack problem stored in burglar.mat and instigate a
global search. At each node, so long as the current solution is
both LP optimal and integer infeasible, we truncate the solution
values to create a feasible integer solution. We then update the
cutoff, if the new objective value has improved it, and continue
the search.
(c) 2017 Fair Isaac Corporation
***********************************************************************/
#include
#include
#include "xprs.h" /* Optimizer header file */
XPRSprob probg;
int XPRS_CC truncsol(XPRSprob prob, void* data, int *feas);
void XPRS_CC optimizermsg(XPRSprob prob, void* data, const char *sMsg,int nLen,int nMsgLvl);
void errormsg(const char *sSubName,int nLineNo,int nErrCode);
/* Global variables */
double *x; /* Nodal LP solution values */
double *gpObjCoef; /* Objective function coefficients */
double gdIntTol; /* Integer feasibility tolerance */
int gnCol; /* Number of columns */
int main()
{
int nReturn; /* Return value of Optimizer subroutine */
int nOptimizerVersion; /* Optimizer version number */
char sProblem[]="..\\data\\burglar";/* Problem name */
char sLogFile[]="knapsack.log"; /* Log file name */
int nExpiry;
char cOptMessage[200];
char banner[256];
/* Initialise Optimizer */
nReturn=XPRSinit(NULL);
XPRSgetbanner(banner); printf("%s",banner);
if (nReturn == 8) return(1);
nReturn=XPRScreateprob(&probg);
if (nReturn != 0 && nReturn != 32) errormsg("XPRScreateprob",__LINE__,nReturn);
/* Delete 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 disallow cuts - to slow solution and allow the
effect of the heuristic to be seen */
if (nReturn=XPRSsetintcontrol(probg,XPRS_PRESOLVE,0)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);
if (nReturn=XPRSsetintcontrol(probg,XPRS_CUTSTRATEGY,0)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);
if (nReturn=XPRSsetintcontrol(probg,XPRS_HEURSTRATEGY,0)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);
/* Read the problem file */
if (nReturn=XPRSreadprob(probg,sProblem,"")) errormsg("XPRSreadprob",__LINE__,nReturn);
/*** Prepare to apply the heuristic ***/
/* Get the number of columns */
if (nReturn=XPRSgetintattrib(probg,XPRS_COLS,&gnCol)) errormsg ("XPRSgetintattrib",__LINE__,nReturn);
/* Allocate memory to the coefficient and solution arrays */
gpObjCoef=malloc(gnCol*sizeof(double));
x=malloc(gnCol*sizeof(double));
if (!gpObjCoef || !x) errormsg("malloc",__LINE__,-1);
/* Get the objective function coefficients */
if (nReturn=XPRSgetobj(probg,gpObjCoef,0,gnCol-1)) errormsg("XPRSgetobj",__LINE__,nReturn);
/* Get integer feasibility tolerance */
if (nReturn=XPRSgetdblcontrol(probg,XPRS_MIPTOL,&gdIntTol))
errormsg ("XPRSgetdblcontrol",__LINE__,nReturn);
/* Tell Optimizer to print global information to the log file at each node */
if (nReturn=XPRSsetintcontrol(probg,XPRS_MIPLOG,3)) errormsg ("XPRSsetintcontrol",__LINE__,nReturn);
/* Tell Optimizer to call truncsol at each node and apply the heuristic */
nReturn=XPRSsetcboptnode(probg,&truncsol,NULL);
/*** Perform the global search - in the course of which the heuristic will
be applied ***/
printf("Applying a primal heuristic to problem %s:-\n\n",sProblem);
if (nReturn=XPRSmaxim(probg,"g")) errormsg("XPRSmaxim",__LINE__,nReturn);
/* free memory and close files */
free(gpObjCoef);
free(x);
if (nReturn=XPRSdestroyprob(probg)) errormsg("XPRSdestroyprob",__LINE__,nReturn);
if (nReturn=XPRSfree()) errormsg("XPRSfree",__LINE__,nReturn);
return 0;
}
/**********************************************************************************\
* Name: truncsol *
* Purpose: Truncate the LP nodal solution values to create a feasible integer *
* solution, and update the cutoff value if the new objective value *
* has improved it. The heuristic is only applied when the nodal *
* solution is both LP optimal and integer infeasible. *
* This function is called at each node in the global search. *
* Arguments: None *
* Return Value: 0 *
\**********************************************************************************/
int XPRS_CC truncsol(XPRSprob prob, void* data, int *feas)
{
int nReturn; /* Return value of Optimizer subroutine */
int nNodNum; /* Number of nodes solved */
double dObjVal; /* Objective value */
double dCutoff; /* Cutoff value */
int nLPStatus; /* LP solution status */
int nIntInf; /* Number of integer infeasibilities */
int i; /* Loop counter */
int solfile; /* save SOLUTIONFILE status */
double dHeurObj; /* Objective value after the solution values
have been truncated*/
char *sLPStatus[]= /* LP solution status - literal version */
{"Optimal","Infeasible","Objective worse than cutoff",
"Unfinished","Unbounded","Cutoff in dual"};
/* Get the current node number */
if (nReturn=XPRSgetintattrib(probg,XPRS_NODES,&nNodNum))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/* Get objective value at the current node */
if (nReturn=XPRSgetdblattrib(probg,XPRS_LPOBJVAL,&dObjVal))
errormsg("XPRSgetdblattrib",__LINE__,nReturn);
/* Get the current cutoff value */
if (nReturn=XPRSgetdblcontrol(probg,XPRS_MIPABSCUTOFF,&dCutoff))
errormsg("XPRSgetdblcontrol",__LINE__,nReturn);
/* Get LP solution status and the number of integer infeasibilities */
if (nReturn=XPRSgetintattrib(probg,XPRS_LPSTATUS,&nLPStatus))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
if (nReturn=XPRSgetintattrib(probg,XPRS_MIPINFEAS,&nIntInf))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/* Apply heuristic if nodal solution is LP optimal and integer infeasible */
if (nLPStatus == 1 && nIntInf>0) {
/* get solution from memory */
if (nReturn=XPRSgetintcontrol(probg,XPRS_SOLUTIONFILE,&solfile))
errormsg("XPRSgetintcontrol",__LINE__,nReturn);
if (nReturn=XPRSsetintcontrol(probg,XPRS_SOLUTIONFILE,0))
errormsg("XPRSsetintcontrol",__LINE__,nReturn);
/* Get LP solution */
if (nReturn=XPRSgetsol(probg,x,NULL,NULL,NULL))
errormsg("XPRSgetsol",__LINE__,nReturn);
/* restore original setting of SOLUTIONFILE */
if (nReturn=XPRSsetintcontrol(probg,XPRS_SOLUTIONFILE,solfile))
errormsg("XPRSsetintcontrol",__LINE__,nReturn);
/* Truncate each solution value - making allowance for the integer
tolerance - and calculate the new "heuristic" objective value */
for (dHeurObj=0, i=0; i dCutoff) {
if (nReturn=XPRSsetdblcontrol(probg,XPRS_MIPABSCUTOFF,dHeurObj + 0.9999))
errormsg("XPRSsetdblcontrol",__LINE__,nReturn);
printf(" ** Cutoff updated to %g **\n\n",dHeurObj+1.0);
}
}
/* If the nodal solution is not LP optimal do not apply the heuristic */
else if (nLPStatus != 1) {
printf(" Node %d: LP solution not optimal, not applying heuristic\n",nNodNum);
printf(" (%s)\n\n",sLPStatus[nLPStatus-1]);
}
/* If the nodal solution is integer feasible print the objective value */
else if (nIntInf == 0)
printf(" Node %d: Integer solution found: Objective Value %g\n\n",
nNodNum,dObjVal);
return 0;
}
/**********************************************************************************\
* Name: optimizermsg *
* Purpose: Display Optimizer error messages and warnings. *
* Arguments: const char *sMsg Message string *
* int nLen Message length *
* int nMsgLvl Message type *
* Return Type: None *
\**********************************************************************************/
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: 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);
}
|