| |||||||||||
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
Source Files By clicking on a file name, a preview is opened at the bottom of this page.
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-2024 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* data, XPRSbranchobject branch, XPRSbranchobject* p_newbranch) { int returnCode = 0; double dDist, dUpDist, dDownDist, dGreatestDist; int iCol; int branchCol = -1; solutionData *nodeData = (solutionData*)data; XPRSbranchobject newbranch = NULL; (void)branch; /* Not interested in what Xpress has planned. */ /* Get solution in the presolved space. */ CHECK_RETURN( XPRSgetpresolvesol(prob, (*nodeData).dSolution, NULL, NULL, NULL) ); /* Find the most fractional column. */ dGreatestDist = 0; 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 ) { branchCol = iCol; dGreatestDist = dDist; } } } /* If we found a column to branch on then create a branching object * (in the presolved space) that reflects branching on that column and * return it to the caller. */ if (branchCol >= 0) { double bndU = floor(nodeData->dSolution[branchCol]); double bndL = ceil(nodeData->dSolution[branchCol]); if ( XPRS_bo_create(&newbranch, prob, 0) || XPRS_bo_addbranches(newbranch, 2) || XPRS_bo_addbounds(newbranch, 0, 1, "U", &branchCol, &bndU) || XPRS_bo_addbounds(newbranch, 1, 1, "L", &branchCol, &bndL) ) goto cleanup; *p_newbranch = newbranch; newbranch = NULL; } cleanup: if (newbranch != NULL) XPRS_bo_destroy(newbranch); 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( XPRSaddcbchgbranchobject(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; } } | |||||||||||
© Copyright 2024 Fair Isaac Corporation. |