FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Branching rule branching on the most violated Integer/Binary

Description
Demonstrates the Xpress Optimizer change branch callbacks

Further explanation of this example: 'Xpress Optimizer Reference Manual', Section 5.6 Using the Callbacks

mostviolated.zip[download all files]

Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
mostviolated.c[download]





mostviolated.c

/***********************************************************************
   Xpress Optimizer Examples
   =========================

   file mostviolated.c
   ```````````````````
   A Branching rule branching on the most violated Integer/Binary

   Demonstrate the Xpress-MP change branch callbacks.

   (c) 2017 Fair Isaac Corporation
***********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "xprs.h"

/* 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 int callbackError = 0;       /* Indicates an error in a callback. */

typedef struct {
  double* dSolution;
  char* cType;
  double dTolerance;
  int nColumns;
} solutionData;

static void XPRS_CC messagecb(XPRSprob cbprob, void* cbdata,
                              const char *msg, int len, int msgtype);

/* Branch on the most fractional integer */
static void XPRS_CC variableSelection(XPRSprob prob, void* vdata, int *iColumn,
                                      int* iUp, double* dEstimate )
{
  int returnCode = 0;
  double dDist, dUpDist, dDownDist,  dGreatestDist;
  int iCol;
  solutionData *nodeData = (solutionData*) vdata;

  (void)iUp;       /* unused */
  (void)dEstimate; /* unused */

  dGreatestDist = 0;
  CHECK_RETURN( XPRSgetpresolvesol(prob, (*nodeData).dSolution, NULL, NULL,
                                   NULL) );
  for( iCol = 0; iCol < (*nodeData).nColumns; iCol++ ) {
    if( (*nodeData).cType[iCol] == 'I' || (*nodeData).cType[iCol] == 'B' ) {
      dUpDist = ceil((*nodeData).dSolution[iCol]) -
        (*nodeData).dSolution[iCol];
      dDownDist = (*nodeData).dSolution[iCol] -
        floor((*nodeData).dSolution[iCol]);
      dDist = (dUpDist>dDownDist)?dUpDist:dDownDist;
      if( dDownDist > (*nodeData).dTolerance && dUpDist >
          (*nodeData).dTolerance )
		if( dDist > dGreatestDist ) {
          *iColumn = iCol;
          dGreatestDist = dDist;
		}
    }
  }

 cleanup:
  if (returnCode) {
    /* There was an error in the callback. We have to stop the optimizer
     * and also set a global flag that indicates that failure.
     */
    int errorCode = -1;
    char errorMessage[512] = {0};
    XPRSgetintattrib(prob, XPRS_ERRORCODE, &errorCode);
    XPRSgetlasterror(prob, errorMessage);
    fprintf(stderr, "Error %d in callback: %s\n", errorCode, errorMessage);
    callbackError = 1;
    XPRSinterrupt(prob, XPRS_STOP_USER);
  }
}


int main( int argc, char *argv[] )
{
  int returnCode = 0;
  XPRSprob prob = NULL;
  FILE* logFile = NULL;
  solutionData nodeData = {0};
  char message[512];                      /* For early error messages */

  /* Check number of arguments and tell user to add an input file otherwise. */
  if (argc != 2) {
    printf("syntax: mostviolated <filename> \n");
    return 1;
  }

  logFile = fopen("mvb.log","w+");
  if ( logFile == NULL ) {
    perror("fopen");
    return 1;
  }

  /* Initialize the optimizer. */
  if ( XPRSinit("") != 0 ) {
    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( XPRSreadprob(prob, argv[1], "") );

  printf("Start solving problem '%s'.\n", argv[1]);
  CHECK_RETURN( XPRSmipoptimize(prob,"l") );
  if (callbackError) {
    returnCode = -3;
    goto cleanup;
  }

  CHECK_RETURN( XPRSsetintcontrol(prob, XPRS_MIPLOG, 3) );
  CHECK_RETURN( XPRSsetintcontrol(prob, XPRS_CUTSTRATEGY, 0) );

  /* setup data */
  CHECK_RETURN( XPRSgetintattrib(prob, XPRS_COLS, &(nodeData.nColumns)) );
  CHECK_RETURN( XPRSgetdblcontrol(prob, XPRS_MATRIXTOL, &(nodeData.dTolerance))
    );
  nodeData.dSolution = malloc(sizeof(double)*nodeData.nColumns);
  nodeData.cType = malloc(sizeof(char)*nodeData.nColumns);
  if (!nodeData.dSolution || !nodeData.cType) {
    perror("malloc");
    returnCode = -2;
    goto cleanup;
  }
  CHECK_RETURN( XPRSgetcoltype(prob, nodeData.cType, 0, nodeData.nColumns-1) );

  CHECK_RETURN( XPRSaddcbchgbranch(prob, variableSelection, &nodeData, 0) );

  CHECK_RETURN( XPRSmipoptimize(prob,"") );
  if (callbackError) {
    returnCode = -3;
    goto cleanup;
  }

 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];
      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).
   */

  free(nodeData.dSolution);
  free(nodeData.cType);

  XPRSfree();
  printf("Solving complete.\n");
  if (logFile != NULL)
    fclose(logFile);
  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;
  }
}

Back to examples browserPrevious exampleNext example