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

Apply an integer fixing heuristic to a MIP problem

Description

We take the power generation problem stored in hpw15.mat which seeks to optimise the operating pattern of a group of electricity generators. We solve this MIP with a very loose integer tolerance and then fix all binary and integer variables to their rounded integer values, changing both their lower and upper bounds. We then solve the resulting LP.

The results are displayed on screen and the problem statistics stored in a logfile.



Source Files

Data Files





roundint.c

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

   file roundint.c
   ```````````````
   Apply an integer fixing heuristic to a MIP problem. The program
   also demonstrates the use of the integer solution callback.

   Description: We take the power generation problem stored in hpw15.mat which
   seeks to optimise the operating pattern of a group of electricity
   generators. We solve this MIP with a very loose integer tolerance
   and then fix all binary and integer variables to their rounded
   integer values, changing both their lower and upper bounds. We then
   solve the resulting LP.
   The results are displayed on screen and the problem statistics
   stored in a logfile.

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


#include <stdio.h>
#include <stdlib.h>
#include "xprs.h"                      /* Optimizer header file */

XPRSprob probg;

#define TOL 0.3                        /* Integer tolerance */

void XPRS_CC intsol(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);


int main()
{
   int nReturn;                        /* Return value of Optimizer subroutine */
   int nOptimizerVersion;              /* Optimizer version number */
   char sProblem[]="hpw15";            /* Problem name */
   char sLogFile[]="roundint.log";     /* Log file name */
   int nExpiry;

   int nCol;                           /* Number of columns */

   /* Global problem information */
   int nGlEnt;                         /* Number of global entities: binary, integer,
                                          semi-continuous and partial integer variables */
   int nSet;                           /* Number of S1 and S2 sets */
   int *pGlInd;                        /* Column indices of the global entities */
   char *pGlType;                      /* Global entity types

   /* Bound changes */
   int *pBndInd;                       /* Column indices of the bounds to be changed */
   char *pBndType;                     /* New bound types - always 'B', since both the upper
                                          and lower bounds are to be changed */
   double *pBndVal;                    /* New bound values */
   int nBnd;                           /* Bound counter */
   int i;                              /* Loop counter */
   int j;                              /* Holder for the bound indices */

   /* Solution information */
   double *x,*y;                       /* MIP and LP solution values */
   double dObjVal;                     /* Objective function value */

   char banner[256];


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

   /* Disable cuts - or the optimal solution will be found at the top node
      and the integer solution callback will hardly be used */
   if (nReturn=XPRSsetintcontrol(probg,XPRS_CUTSTRATEGY,0))
   	   errormsg("XPRSsetintcontrol",__LINE__,nReturn);

   /* Read the problem file */
   if (nReturn=XPRSreadprob(probg,sProblem,"")) errormsg("XPRSreadprob",__LINE__,nReturn);

   /*** Solve MIP with loose integer tolerance ***/

   /* Set integer feasibility tolerance */
   if (nReturn=XPRSsetdblcontrol(probg,XPRS_MIPTOL,TOL)) errormsg("XPRSsetdblcontrol",__LINE__,nReturn);

   /* Tell Optimizer to print out global information at each node and call intsol
      whenever an integer solution is found */
   if (nReturn=XPRSsetintcontrol(probg,XPRS_MIPLOG,3)) errormsg("XPRSsetintcontrol",__LINE__,nReturn);
   nReturn=XPRSsetcbintsol(probg,&intsol,NULL);

   /* Get the number of columns */
   if (nReturn=XPRSgetintattrib(probg,XPRS_COLS,&nCol)) errormsg("XPRSgetintattrib",__LINE__,nReturn);

   /* Allocate memory for MIP solution array and check for memory shortage */
   x=malloc(nCol * sizeof(double));
   if (!x) errormsg("malloc",__LINE__,-1);

   /* Solve the MIP problem and get the solution values */
   printf("Applying an integer fixing heuristic to problem %s:-\n\n",sProblem);
   printf("Solving MIP with global:\n\n");
   if (nReturn=XPRSmipoptimize(probg,"")) errormsg("XPRSmipoptimize",__LINE__,nReturn) ;
   if (nReturn=XPRSgetmipsol(probg,x,NULL)) errormsg("XPRSgetmipsol",__LINE__,nReturn);

   /*** Round off the values of all binary and integer variables  ***/

   /* Allocate memory for global entity arrays */
   pGlInd=malloc(nCol * sizeof(int));
   pGlType=malloc(nCol * sizeof(char));
   if (!pGlInd || !pGlType) errormsg("malloc",__LINE__,-1);

   /* Retrieve global entity information */
   if (nReturn=XPRSgetglobal(probg,&nGlEnt,&nSet,pGlType,pGlInd,NULL,NULL,NULL,NULL,NULL))
       errormsg("XPRSgetglobal",__LINE__,nReturn);

   /* Allocate memory for bound arrays */
   pBndInd=malloc(nGlEnt * sizeof(int));
   pBndVal=malloc(nGlEnt * sizeof(double));
   pBndType=malloc(nGlEnt * sizeof(char));
   if (!pBndInd || !pBndVal || !pBndType) errormsg("malloc",__LINE__,-1);

   /* Initialise bound counter */
   nBnd = 0;

   /* Go through global entities */
   for(i=0; i<nGlEnt; i++) {

      /* Test whether each is a binary or integer variable */
      if (pGlType[i] == 'B' || pGlType[i] == 'I') {

         /* Hold the index of the variable */
         j = pGlInd[i];

         /* Store the index, round the variable's value to the nearest integer,
         and reset both its upper and lower bounds */
         pBndInd[nBnd]=j;
         pBndVal[nBnd]=(double) (int)(x[j]+0.5);
         pBndType[nBnd]='B';
         nBnd++;
      }
   }

   /* Instruct Optimizer to change the bounds */
   if (nReturn=XPRSchgbounds(probg,nBnd,pBndInd,pBndType,pBndVal))
      errormsg("XPRSchgbounds",__LINE__,nReturn);
   printf("\nAfter global the %d binary and integer variables were fixed\n\n",nBnd);

   /*** Solve the resulting LP ***/

   /* Allocate memory for LP solution array and check for memory shortage */
   y=malloc(nCol * sizeof(double));
   if (!y) errormsg("malloc",__LINE__,-1);

   /* Solve the LP and get the solution values */
   if (nReturn=XPRSlpoptimize(probg,"")) errormsg("XPRSlpoptimize",__LINE__,nReturn);
   if (nReturn=XPRSgetlpsol(probg,y,NULL,NULL,NULL)) errormsg("XPRSgetlpsol",__LINE__,nReturn);

   /* Get and print the LP objective function value */
   if (nReturn=XPRSgetdblattrib(probg,XPRS_LPOBJVAL,&dObjVal))
   		errormsg("XPRSgetdblattrib",__LINE__,nReturn);
   printf("After solving the LP the final objective value was %g\n\n",dObjVal);

   /* Print the non-zero MIP and corresponding LP solution values for comparison:*/
   printf("The non-zero MIP and LP solution values are:\n\n");
   for(i=0; i<nCol; i++) if(x[i]) printf("   x[%2d] = %5.1f  %5.3g\n",i,x[i],y[i]);
   printf("\n");

   /* Free memory, close files */
   free(x);
   free(pGlInd);
   free(pGlType);
   free(pBndInd);
   free(pBndVal);
   free(pBndType);
   free(y);

   if (nReturn=XPRSdestroyprob(probg)) errormsg("XPRSdestroyprob",__LINE__,nReturn);
   if (nReturn=XPRSfree()) errormsg("XPRSfree",__LINE__,nReturn);

   return(0);
}


/**********************************************************************************\
* Name:         intsol                                                             *
* Purpose:      Displays the objective value associated with a node in the global  *
*               search. This function is called every time an integer solution has *
*               been found.                                                        *
* Arguments:    None                                                               *
* Return Value: 0                                                                  *
\**********************************************************************************/

void XPRS_CC intsol(XPRSprob prob, void* data)
{
   int nReturn;             /* Return value of Optimizer subroutine */
   int nNode;               /* Node number */
   double dObjVal;          /* Objective function value */

   /* Get the node number */
   if (nReturn=XPRSgetintattrib(prob,XPRS_NODES,&nNode)) errormsg("XPRSgetintattrib",__LINE__,nReturn);

   /* Get the objective function value */
   if (nReturn=XPRSgetdblattrib(prob,XPRS_LPOBJVAL,&dObjVal)) errormsg("XPRSgetdblattrib",__LINE__,nReturn);

   /* Print the node number and the associated objective value */
   printf("   Node %d (Objective value = %g)\n",nNode,dObjVal);

   return;
}


/**********************************************************************************\
* Name:         optimizermsg                                                       *
* Purpose:      Display Optimizer error messages and warnings.                     *
* Arguments:    const char *sMsg       Message string                              *
*               int nLen               Message length                              *
*               int nMsgLvl            Message type                                *
* Return Type:  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:      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);
}



Back to examples browserPrevious exampleNext example