/***********************************************************************
Xpress Optimizer Examples
=========================
file savesol.c
```````````````
Show how to save a postsolved solution to memory and access the
results of a global search. The program demonstrates the use of the
integer solution callback.
We take the knapsack problem in burglar.mps and instigate a global
search. Whenever an integer solution is found it is postsolved,
stored in memory, and printed to an output file. The best and final
solution values, and other global search information, are displayed
on screen. A log file is also created.
(c) 2017 Fair Isaac Corporation
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "xprs.h" /* Optimizer header file */
XPRSprob probg;
void XPRS_CC printsol(XPRSprob,void* data);
void XPRS_CC optimizermsg(XPRSprob prob,void* data,const char *sMsg,int nLen,int nMsgLvl);
void errormsg(const char *sSubName,int nLineNo,int nErrCode);
FILE *pOutput; /* Pointer to the output file */
int gnCol; /* Number of columns in the problem matrix */
double *gpIntSol; /* Integer solution values */
main()
{
int nReturn; /* Return value of Optimizer subroutine */
int nOptimizerVersion; /* Optimizer version number */
char sProblem[]="burglar"; /* Problem name */
char sOutFile[]="savesol.out"; /* Output file name */
char sLogFile[]="savesol.log"; /* Log file name */
int nExpiry;
int nSol; /* Number of integer solutions found */
double dBestObj; /* Best objective value found */
int nNodes; /* Number of nodes solved in the global search */
int nActNodes; /* Number of active nodes ignored by the search */
int nLastNode; /* Node at which the last integer solution was found */
double dBestBnd; /* Best bound found in the global search */
int nGlStatus; /* Global search status - complete, incomplete, etc */
int i; /* Loop counter*/
char banner[XPRS_MAXBANNERLENGTH];
/* Delete and open output file */
remove(sOutFile);
pOutput=fopen(sOutFile,"w");
/* 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);
/* 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);
/* Alow no cuts - so the problem does not solve too quickly */
if (nReturn=XPRSsetintcontrol(probg,XPRS_CUTSTRATEGY,0))
errormsg("XPRSsetintcontrol",__LINE__,nReturn);
/* Read the problem file */
if (nReturn=XPRSreadprob(probg,sProblem,"")) errormsg("XPRSreadprob",__LINE__,nReturn);
/*** Tell Optimizer to postsolve every integer solution found, save it to memory and
print the solution values to the output file ***/
/* Call function printsol whenever an integer solution is found */
nReturn=XPRSsetcbintsol(probg,printsol,NULL);
/* Get the number of columns and allocate space for the solution array */
if (nReturn=XPRSgetintattrib(probg,XPRS_COLS,&gnCol))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
gpIntSol=malloc(gnCol*sizeof(double));
if (!gpIntSol) errormsg("malloc",__LINE__,-1);
/*** Search for integer solutions ***/
printf("Solving problem %s:\n\n",sProblem);
fprintf(pOutput,"Solving problem %s:\n\n",sProblem);
if (nReturn=XPRSchgobjsense(probg,XPRS_OBJ_MAXIMIZE)) errormsg ("XPRSchgobjsense",__LINE__,nReturn);
if (nReturn=XPRSmipoptimize(probg,"")) errormsg("XPRSmipoptimize",__LINE__,nReturn);
/*** Retrieve the results of the global search ***/
/* Get the number of integer solutions found */
if (nReturn=XPRSgetintattrib(probg,XPRS_MIPSOLS,&nSol))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/* Get the objective value of the best integer solution found */
if (nReturn=XPRSgetdblattrib(probg,XPRS_MIPOBJVAL,&dBestObj))
errormsg("XPRSgetdblattrib",__LINE__,nReturn);
/* Get the number of outstanding nodes */
if (nReturn=XPRSgetintattrib(probg,XPRS_ACTIVENODES,&nActNodes))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/* Get the node at which the last feasible integer solution was found */
if (nReturn=XPRSgetintattrib(probg,XPRS_MIPSOLNODE,&nLastNode))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/* Get the number of nodes solved */
if (nReturn=XPRSgetintattrib(probg,XPRS_NODES,&nNodes))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/* Get the value of the best bound */
if (nReturn=XPRSgetdblattrib(probg,XPRS_BESTBOUND,&dBestBnd))
errormsg("XPRSgetdblattrib",__LINE__,nReturn);
/* Get the global status */
if (nReturn=XPRSgetintattrib(probg,XPRS_MIPSTATUS,&nGlStatus))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/*** Display the results of the global search ***/
switch (nGlStatus) {
case 3:
printf("Global search incomplete\n\n");
printf(" No integer solution found\n");
printf(" %d nodes searched\n",nNodes);
printf(" %d nodes remaining in search\n",nActNodes);
printf(" Best bound %g\n\n",dBestBnd);
break;
case 4:
printf("Global search incomplete\n\n");
printf(" %d integer solution%s found\n",nSol,(nSol==1) ? "" : "s");
printf(" %d nodes searched\n",nNodes);
printf(" %d nodes remaining in search\n",nActNodes);
printf(" Best bound %g\n\n",dBestBnd);
printf(" Best integer solution at node %d\n\n",nLastNode);
printf(" Objective value %g\n\n",dBestObj);
printf(" Solution values\n");
for (i=0; i<gnCol; i++)
printf(" x[%d]=%g\n",i,gpIntSol[i]);
printf("\n");
break;
case 5:
printf("Global search complete\n\n");
printf(" No integer solution found\n");
printf(" %d nodes searched\n",nNodes);
printf(" Best bound %g\n",dBestBnd);
break;
case 6:
printf("Global search complete\n\n");
printf(" %d nodes searched\n",nNodes);
printf(" %d integer solution%s found\n\n",nSol,(nSol==1) ? "" : "s");
printf(" Best integer solution at node %d\n\n",nLastNode);
printf(" Objective value %g\n\n",dBestObj);
printf(" Solution values\n");
for (i=0; i<gnCol; i++)
printf(" x[%d]=%g\n",i,gpIntSol[i]);
printf("\n");
break;
default:
printf("Global search did not take place\n\n");
break;
}
/* Free memory and close files */
free(gpIntSol);
if (nReturn=XPRSdestroyprob(probg)) errormsg("XPRSdestroyprob",__LINE__,nReturn);
if (nReturn=XPRSfree()) errormsg("XPRSfree",__LINE__,nReturn);
return 0;
}
/**********************************************************************************\
* Name: printsol *
* Purpose: Save the postsolved nodal integer solution to memory, retrieve it *
* and print the solution values to the output file. *
* The function is called when an integer solution is found at a node *
* in the branch and bound tree. *
* Arguments: None *
* Return Value: None *
\**********************************************************************************/
void XPRS_CC printsol(XPRSprob prob, void* data)
{
int nReturn; /* Return value of Optimizer subroutine */
int nNodeNum; /* Current node number */
double dObjVal; /* Objective value of the nodal integer solution */
int i; /* Loop counter */
/* Get the current node number */
if (nReturn=XPRSgetintattrib(probg,XPRS_NODES,&nNodeNum))
errormsg("XPRSgetintattrib",__LINE__,nReturn);
/* Get the objective value of the current integer solution */
if (nReturn=XPRSgetdblattrib(probg,XPRS_MIPOBJVAL,&dObjVal))
errormsg("XPRSgetdblattrib",__LINE__,nReturn);
/* Retrieve the postsolved solution values from memory */
if (nReturn=XPRSgetmipsol(probg,gpIntSol,NULL))
errormsg("XPRSgetmipsol",__LINE__,nReturn);
/* Print the solution to the output file */
fprintf(pOutput,"Node %d\n",nNodeNum);
fprintf(pOutput," Integer solution has objective value %g\n",dObjVal);
fprintf(pOutput," Postsolved solution values are:\n");
for (i=0; i<gnCol; i++)
fprintf(pOutput," x[%d]=%g\n",i,gpIntSol[i]);
fprintf(pOutput,"\n");
}
/**********************************************************************************\
* Name: optimizermsg *
* Purpose: To display Optimizer error messages and warnings. *
* Arguments: const char *sMsg Message string *
* int nLen Message length *
* int nMsgLvl Message type *
* Return Value: 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: 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);
}
|