| /***********************************************************************
   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-2024 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;
  }
}
 |