/***********************************************************************
Xpress Optimizer Examples
=========================
file mipsolenum.c
`````````````````
Find the 10 best solutions with the MIP solution enumerator
We take the power generation problem stored in hpw15.mps which seeks to
optimise the operating pattern of a group of electricity generators. We
run the MIP solution enumerator on the problem using the default setup
obtaining the best 10 solutions. The best 10 solutions are stored to a
MIP solution pool. The solutions' objectives and solution values are
printed to screen.
(c) 2017-2025 Fair Isaac Corporation
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "xprs.h" /* Optimizer header file */
#include "xprs_mse_defaulthandler.h" /* 'Default' enumerated mip solution
handler */
/* Calls an Xpress optimizer function and checks the return code.
* If the call fails then the function
* - prints a short error message to stderr,
* - sets variable 'returnCode' to the error,
* - and branches to label 'cleanup'.
*/
#define CHECK_RETURN(call) do { \
int result_ = call; \
if ( result_ != 0 ) { \
fprintf(stderr, "Line %d: %s failed with %d\n", \
__LINE__, #call, result_); \
returnCode = result_; \
goto cleanup; \
} \
} while (0)
static void XPRS_CC messagecb(XPRSprob cbprob, void* cbdata,
const char *msg, int len, int msgtype);
int main(void) {
int returnCode = 0;
XPRSprob prob = NULL;
XPRSmipsolpool msp = NULL;
XPRSmipsolenum mse = NULL;
int nMaxSols;
int i, j, nSols, nCols, iSolutionId, iSolutionIdStatus;
double dObj, dSol;
const char *sProblem = "../data/hpw15";
/* Initialize the optimizer. */
if ( XPRSinit("") != 0 ) {
char message[512];
XPRSgetlicerrmsg(message, sizeof(message));
fprintf(stderr, "Licensing error: %s\n", message);
return 1;
}
/* Create a new problem and immediately register a message handler.
* Once we have a message handler installed, errors will produce verbose
* error messages on the console and we can limit ourselves to minimal
* error handling in the code here.
*/
CHECK_RETURN( XPRScreateprob(&prob) );
CHECK_RETURN( XPRSaddcbmessage(prob, messagecb, NULL, 0) );
CHECK_RETURN( XPRS_mse_create(&mse) );
CHECK_RETURN( XPRS_msp_create(&msp) );
CHECK_RETURN( XPRSreadprob(prob, sProblem, "") );
CHECK_RETURN( XPRSgetintattrib(prob, XPRS_COLS, &nCols) );
/* Avoid duplicated solutions from heuristics. */
CHECK_RETURN( XPRS_msp_setintcontrol(msp, XPRS_MSP_DUPLICATESOLUTIONSPOLICY,
3) );
/* Disable dual reductions to prevent dominated solutions from being */
/* presolved away. */
CHECK_RETURN( XPRSsetintcontrol(prob, XPRS_MIPDUALREDUCTIONS, 2) );
/* Run the enumeration */
nMaxSols = 10;
CHECK_RETURN( XPRS_mse_minim(mse, prob, msp, XPRS_mse_defaulthandler, NULL,
&nMaxSols) );
/* Print out the solutions found */
CHECK_RETURN( XPRS_mse_getintattrib(mse, XPRS_MSE_SOLUTIONS, &nSols) );
for(i = 1; i <= nSols; i++) {
CHECK_RETURN( XPRS_mse_getsollist(mse, XPRS_MSE_METRIC_MIPOBJECT, i, i,
&iSolutionId, NULL, NULL) );
CHECK_RETURN( XPRS_mse_getsolmetric(mse, iSolutionId, &iSolutionIdStatus,
XPRS_MSE_METRIC_MIPOBJECT, &dObj) );
printf("--------\n%3i = %12.5f\n", i, dObj);
for(j = 0; j < nCols; j++) {
CHECK_RETURN( XPRS_msp_getsol(msp, iSolutionId, &iSolutionIdStatus,
&dSol, j, j, NULL) );
printf("%3i = %12.5f\n", j, dSol);
}
}
cleanup:
if (returnCode > 0) {
/* There was an error with the solver. Get the error code and error message.
* If prob is still NULL then the error was in XPRScreateprob() and
* we cannot find more detailed error information.
*/
if (prob != NULL) {
int errorCode = -1;
char errorMessage[512] = {0};
XPRSgetintattrib(prob, XPRS_ERRORCODE, &errorCode);
XPRSgetlasterror(prob, errorMessage);
fprintf(stderr, "Error %d: %s\n", errorCode, errorMessage);
}
}
/* Free the resources (variables are initialized so that this is valid
* even in case of error).
*/
XPRS_msp_destroy(msp);
XPRSdestroyprob(prob);
XPRS_mse_destroy(mse);
XPRSfree();
return returnCode;
}
/* XPRS optimizer message callback */
void XPRS_CC messagecb(XPRSprob cbprob, void* cbdata,
const char *msg, int len, int msgtype)
{
(void)cbprob; /* unused (the problem for which the message is issued) */
(void)cbdata; /* unused (the data passed to XPRSaddcbmessage()) */
switch(msgtype)
{
case 4: /* error */
case 3: /* warning */
case 2: /* not used */
case 1: /* information */
printf("%*s\n", len, msg);
break;
default: /* exiting - buffers need flushing */
fflush(stdout);
break;
}
}
|