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

Goal Programming

Description
Implementation of preemptive and Archimedian Goal Programming algorithms working on objective functions or constraints. The Goal Programming directives are input from the configuration files *.gol.


Source Files

Data Files





goal_example.c

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

   file goal_example.c
   ```````````````````
   Demonstrates how to implement traditional goal programming
   using Xpress.

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

#include "stdlib.h"
#include "stdio.h"
#include "xprs.h"

#include "math.h"
#include "memory.h"
#include "string.h"
#include "ctype.h"

#if defined(WIN32) || defined(_WIN32)
#else
#define strcmpi stricmp
#define stricmp strcasecmp
#define strnicmp strncasecmp
#endif

#define ERROR_EXIT(msg)                                                      \
{                                                                            \
  printf("ERROR:%s(%i):%s\n", __FILE__, __LINE__, msg);                      \
  abort(); /*__asm{ int 3 };;*/                                                                   \
}                                                                            \

#define CHECKED_RETURN(function, args)                                       \
{                                                                            \
  int _nReturn;                                                              \
  if ( ((_nReturn = function args)  !=0 ) )  {                               \
    ERROR_EXIT(#function #args)                                              \
  }                                                                          \
}

static void XPRS_CC Message(XPRSprob prob, void* my_object, const char *msg, int len, int msgtype)
{
  switch(msgtype)
  {
  case 4: /* error */
  case 3: /* warning */
  case 2: /* dialogue */
  case 1: /* information */
    printf("%s\n", msg);
    break;
  default: /* exiting - buffers need flushing */
    fflush(stdout);
    break;
  }

}

struct GoalConstraint_s {
  double dCost;
  int iRow;
};
typedef struct GoalConstraint_s * GoalConstraint;

struct GoalObjective_s {
  double dTolerance;
  int iRow;
  int iOptimizationSense;
  int bFractionIsPercentage;
};
typedef struct GoalObjective_s * GoalObjective;

struct SlackPair_s {
  int iSlack_Pos;
  int iSlack_Neg;
};
typedef struct SlackPair_s * SlackPair;

struct Goal_s {
  int bArchimedianOtherwisePreemptive;
  int bConstraintsOtherwiseObjective;
  GoalConstraint gc;
  int gc_count;
  GoalObjective go;
  int go_count;
};
typedef struct Goal_s * Goal;

static void AddSlack(XPRSprob prob, const int iRow, const int iSlackSign, const double dSlackCost, int * const iNewColIndex)
{
  double obj = dSlackCost, dmatval = (iSlackSign > 0 ? 1.0 : -1.0);
  double bdl = 0.0, bdu = XPRS_PLUSINFINITY;
  int mrwind = iRow, mstart[] = {0, 1};

  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_COLS, iNewColIndex) ) /* Slack will go on the end of the column set */
  CHECKED_RETURN( XPRSaddcols, (prob, 1 /*newcol*/, 1 /*newnz*/, &obj, mstart, &mrwind, &dmatval, &bdl, &bdu) )
}

static int GcArray_AddRecord(GoalConstraint *gc, int * const gc_count)
{
  if(!*gc) {
    if(!(*gc = (GoalConstraint) malloc(sizeof(**gc) * (*gc_count + 1)))) {
      goto exit_with_failure;
    }
  } else {
    GoalConstraint gc_temp;
    if(!(gc_temp = (GoalConstraint) realloc(*gc, sizeof(**gc) * (*gc_count + 1)))) {
      goto exit_with_failure;
    }
    *gc = gc_temp;
  }
  (*gc_count)++;
  return 0;
exit_with_failure:;
  return 1;
}

static int GoArray_AddRecord(GoalObjective *go, int * const go_count)
{
  if(!*go) {
    if(!(*go = (GoalObjective) malloc(sizeof(**go) * (*go_count + 1)))) {
      goto exit_with_failure;
    }
  } else {
    GoalObjective go_temp;
    if(!(go_temp = (GoalObjective) realloc(*go, sizeof(**go) * (*go_count + 1)))) {
      goto exit_with_failure;
    }
    *go = go_temp;
  }
  (*go_count)++;
  return 0;
exit_with_failure:;
  return 1;
}

static int SpArray_AddRecord(SlackPair *sp, int * const sp_count)
{
  if(!*sp) {
    if(!(*sp = (SlackPair) malloc(sizeof(**sp) * (*sp_count + 1)))) {
      goto exit_with_failure;
    }
  } else {
    SlackPair sp_temp;
    if(!(sp_temp = (SlackPair) realloc(*sp, sizeof(**sp) * (*sp_count + 1)))) {
      goto exit_with_failure;
    }
    *sp = sp_temp;
  }
  (*sp_count)++;
  return 0;
exit_with_failure:;
  return 1;
}

static void RelaxConstraint(XPRSprob prob, const int iRow, int bArchimedianOtherwisePreemptive, const double dArchimedianWeight, SlackPair *sp, int * const sp_count)
{
  char qrtype;
  double dCost = (bArchimedianOtherwisePreemptive ? dArchimedianWeight : 0.0);
  SlackPair sp_;
  CHECKED_RETURN( XPRSgetrowtype, (prob, &qrtype, iRow, iRow) )
  CHECKED_RETURN( SpArray_AddRecord, (sp, sp_count) )
  sp_ = &(*sp)[*sp_count - 1];
  sp_->iSlack_Pos = -1;
  sp_->iSlack_Neg = -1;
  switch(qrtype) {
  case('N') :
    break;
  case('L') :
  case('P') :
    AddSlack(prob, iRow, -1 /*iSlackSign*/, dCost, &sp_->iSlack_Neg);
    break;
  case('G') :
  case('Q') :
    AddSlack(prob, iRow,  1 /*iSlackSign*/, dCost, &sp_->iSlack_Pos);
    break;
  case('E') :
  case('R') :
    AddSlack(prob, iRow,  1 /*iSlackSign*/, dCost, &sp_->iSlack_Pos);
    AddSlack(prob, iRow, -1 /*iSlackSign*/, dCost, &sp_->iSlack_Neg);
    break;
  default :
    ERROR_EXIT("Unexpected value")
  }
}

static void RunGoal_Preemptive_Constraint(XPRSprob prob, const int bRunMip, GoalConstraint GoalRows, const int iGoalRows_Count, int * const bIsInfeasible)
{
  int i, j, nRows, nCols, iStatus, bHaveBasis;
  double dObjVal, dZero = 0.0, dOne = 1.0;
  SlackPair sp = NULL;
  int sp_count = 0;
  char cBoth = 'B';
  int *rstatus = NULL, *cstatus = NULL;
  int bWriteGoalProbs = 0;

  /* Ensure the problem is in the original state */
  CHECKED_RETURN( XPRSpostsolve, (prob) )

  /* Add the appropriate slacks for the goals */
  for(i = 0; i < iGoalRows_Count; i++) {
    RelaxConstraint(prob, GoalRows[i].iRow, 0 /*bArchimedianOtherwisePreemptive*/, 0.0 /*dArchimedianWeight*/, &sp, &sp_count);
  }

  /* Setup arrays to store basis and zero all costs */
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_ROWS, &nRows) )
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_COLS, &nCols) )

  if(!(rstatus = (int *)malloc(sizeof(int) * nRows))) {
    ERROR_EXIT("Malloc failure")
  }

  if(!(cstatus = (int *)malloc(sizeof(int) * nCols))) {
    ERROR_EXIT("Malloc failure")
  }

  for(j = 0; j < nCols; j++) {
    CHECKED_RETURN( XPRSchgobj, (prob, 1, &j, &dZero) )
  }

  if(bWriteGoalProbs) {
    CHECKED_RETURN( XPRSwriteprob, (prob, "goal\\pc_goal0", "") )
  }

  /* Loop through the goal constraints */
  bHaveBasis = 0;
  for(i = 0; i < sp_count; i++) {

    /* Skip non-binding goal rows */
    if(sp[i].iSlack_Neg < 0 && sp[i].iSlack_Pos < 0) continue;

    /* Set the slack cost(s) on the goal row to 1.0 */
    if(sp[i].iSlack_Neg >= 0) CHECKED_RETURN( XPRSchgobj, (prob, 1, &sp[i].iSlack_Neg, &dOne) )
    if(sp[i].iSlack_Pos >= 0) CHECKED_RETURN( XPRSchgobj, (prob, 1, &sp[i].iSlack_Pos, &dOne) )

    if(bHaveBasis) {
      /* We have a basis from the last goal solve use this to hot start this solve */
      CHECKED_RETURN( XPRSloadbasis, (prob, rstatus, cstatus) )
    }

    if(bWriteGoalProbs) {
      char buff[256];
      sprintf(buff, "goal\\pc_goal%i", i + 1);
      CHECKED_RETURN( XPRSwriteprob, (prob, buff, "") )
    }

    /* Solve the LP and get the solve status */
    CHECKED_RETURN( XPRSmipoptimize, (prob, "l") )
    CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_MIPSTATUS, &iStatus) )

    /* Exit if the problem is infeasible even with the slacks we have added to the rows */
    if(iStatus != XPRS_MIP_OPTIMAL) goto exit_with_infeasible;

    CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_LPOBJVAL, &dObjVal) )
    if(dObjVal != 0.0) {
      /* Exit if we can't satisfy the current goal constraint */
      goto exit_with_infeasible;
    }

    /* Update the hot start basis */
    if(!bHaveBasis) {
      CHECKED_RETURN( XPRSgetbasis, (prob, rstatus, cstatus) )
      bHaveBasis = 1;
    }

    /* Run the MIP search if required */
    if(bRunMip) {
      /* Solve the MIP search and get the solve status */
      CHECKED_RETURN( XPRSmipoptimize, (prob, "") )
      CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_MIPSTATUS, &iStatus) )

      /* Exit if the problem is infeasible even with the slacks we have added to the rows */
      if(iStatus != XPRS_MIP_OPTIMAL) goto exit_with_infeasible;

      CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_MIPOBJVAL, &dObjVal) )
      if(dObjVal != 0.0) {
        /* Exit if we can't satisfy the current goal constraint */
        goto exit_with_infeasible;
      }
    }

    /*
    Restore the problem to the original state and fix the
    slacks on the current goal row to zero ready to process
    the next goal row.
    */
    CHECKED_RETURN( XPRSpostsolve, (prob) )
    if(sp[i].iSlack_Neg >= 0) CHECKED_RETURN( XPRSchgbounds, (prob, 1, &sp[i].iSlack_Neg, &cBoth, &dZero) )
    if(sp[i].iSlack_Pos >= 0) CHECKED_RETURN( XPRSchgbounds, (prob, 1, &sp[i].iSlack_Pos, &cBoth, &dZero) )

  }

  *bIsInfeasible = 0;
  if(sp) free(sp); sp = NULL;
  if(rstatus) free(rstatus); rstatus = NULL;
  if(cstatus) free(cstatus); cstatus = NULL;
  return;
exit_with_infeasible:;
  *bIsInfeasible = 1;
  if(sp) free(sp); sp = NULL;
  if(rstatus) free(rstatus); rstatus = NULL;
  if(cstatus) free(cstatus); cstatus = NULL;
  return;
}

static void RunGoal_Preemptive_Objective(XPRSprob prob, const int bRunMip, GoalObjective GoalObjs, const int iGoalGoalObjs_Count, int * const bIsInfeasible, double * const dObjRhs_)
{
  int i, j, nRows, nCols, iStatus, bHaveBasis, ncoeffs;
  double dObjVal, dZero = 0.0, dOne = 1.0;
  int *rstatus = NULL, *cstatus = NULL;
  int bWriteGoalProbs = 0;
  int mstart[2];
  int *mclind = NULL;
  double *dcmatval = NULL;
  double dRhs, dMatRhs, dMatObRhs;

  /* Ensure the problem is in the original state */
  CHECKED_RETURN( XPRSpostsolve, (prob) )

  /* Setup arrays to store basis and zero all costs */
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_ROWS, &nRows) )
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_COLS, &nCols) )

  if(!(rstatus = (int *)malloc(sizeof(int) * nRows))) {
    ERROR_EXIT("Malloc failure")
  }

  if(!(cstatus = (int *)malloc(sizeof(int) * nCols))) {
    ERROR_EXIT("Malloc failure")
  }

  if(!(mclind = (int *)malloc(sizeof(int) * nCols))) {
    ERROR_EXIT("Malloc failure")
  }

  if(!(dcmatval = (double *)malloc(sizeof(double) * nCols))) {
    ERROR_EXIT("Malloc failure")
  }

  if(bWriteGoalProbs) {
    CHECKED_RETURN( XPRSwriteprob, (prob, "goal\\po_goal0", "") )
  }

  /* Loop through the goal objectives */
  bHaveBasis = 0;
  for(i = 0; i < iGoalGoalObjs_Count; i++) {

    CHECKED_RETURN( XPRSgetrhs, (prob, &dMatRhs, GoalObjs[i].iRow, GoalObjs[i].iRow) )
    CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_OBJRHS, &dMatObRhs) )

    /* Copy the row coefficients into the objective */
    CHECKED_RETURN( XPRSgetrows, (prob, mstart, mclind, dcmatval, nCols, &ncoeffs, GoalObjs[i].iRow, GoalObjs[i].iRow) );
    for(j = 0; j < nCols; j++) {
      CHECKED_RETURN( XPRSchgobj, (prob, 1, &j, &dZero) )
    }
    CHECKED_RETURN( XPRSchgobj, (prob, ncoeffs, mclind, dcmatval) )

    if(bHaveBasis) {
      /* We have a basis from the last goal solve use this to hot start this solve */
      CHECKED_RETURN( XPRSloadbasis, (prob, rstatus, cstatus) )
    }

    if(bRunMip) {
      /* Ensure that we restart the MIP solve each time */
      CHECKED_RETURN( XPRSpostsolve, (prob) )
    }

    if(bWriteGoalProbs) {
      char buff[256];
      sprintf(buff, "goal\\po_goal%i", i + 1);
      CHECKED_RETURN( XPRSwriteprob, (prob, buff, "") )
    }

    /* Solve the LP and get the solve status */
    if(GoalObjs[i].iOptimizationSense >= 0) {
      CHECKED_RETURN(XPRSchgobjsense, (prob,XPRS_OBJ_MINIMIZE) )
    } else {
      CHECKED_RETURN(XPRSchgobjsense, (prob,XPRS_OBJ_MAXIMIZE) )
    }
	CHECKED_RETURN( XPRSmipoptimize, (prob, "l") )
    CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_MIPSTATUS, &iStatus) )

    /* Exit if the problem is infeasible even with the slacks we have added to the rows */
    if(iStatus != XPRS_MIP_LP_OPTIMAL) goto exit_with_infeasible;

    CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_LPOBJVAL, &dObjVal) )

    /* Update the hot start basis */
    if(!bHaveBasis) {
      CHECKED_RETURN( XPRSgetbasis, (prob, rstatus, cstatus) )
      bHaveBasis = 1;
    }

    /* Run the MIP search if required */
    if(bRunMip) {
      /* Solve the MIP search and get the solve status */
      CHECKED_RETURN( XPRSmipoptimize, (prob, "") )
      CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_MIPSTATUS, &iStatus) )

      /* Exit if the problem is infeasible even with the slacks we have added to the rows */
      if(iStatus != XPRS_MIP_OPTIMAL) goto exit_with_infeasible;

      CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_MIPOBJVAL, &dObjVal) )
    }

    /* Constraint the row to the objective we have calculated */
    dObjVal -= dMatRhs + dMatObRhs;
    if(GoalObjs[i].iOptimizationSense >= 0) {
      char qLE = 'L';
      CHECKED_RETURN( XPRSchgrowtype, (prob, 1, &GoalObjs[i].iRow, &qLE) )
      if(GoalObjs[i].bFractionIsPercentage) {
        dRhs = dObjVal + fabs(dObjVal) * GoalObjs[i].dTolerance * 0.01 + dMatRhs;
      } else {
        dRhs = dObjVal + GoalObjs[i].dTolerance + dMatRhs;
      }
    } else {
      char qGE = 'G';
      CHECKED_RETURN( XPRSchgrowtype, (prob, 1, &GoalObjs[i].iRow, &qGE) )
      if(GoalObjs[i].bFractionIsPercentage) {
        dRhs = dObjVal - fabs(dObjVal) * GoalObjs[i].dTolerance * 0.01 + dMatRhs;
      } else {
        dRhs = dObjVal - GoalObjs[i].dTolerance + dMatRhs;
      }
    }
    if(dObjRhs_) *dObjRhs_ = dMatRhs + dMatObRhs;
    CHECKED_RETURN( XPRSchgrhs, (prob, 1, &GoalObjs[i].iRow, &dRhs) )

  }

  *bIsInfeasible = 0;
  if(rstatus) free(rstatus); rstatus = NULL;
  if(cstatus) free(cstatus); cstatus = NULL;
  if(mclind) free(mclind); mclind = NULL;
  if(dcmatval) free(dcmatval); dcmatval = NULL;
  return;
exit_with_infeasible:;
  *bIsInfeasible = 1;
  if(rstatus) free(rstatus); rstatus = NULL;
  if(cstatus) free(cstatus); cstatus = NULL;
  if(mclind) free(mclind); mclind = NULL;
  if(dcmatval) free(dcmatval); dcmatval = NULL;
  return;
}

static void RunGoal_Archimedian_Constraint(XPRSprob prob, const int bRunMip, GoalConstraint GoalRows, const int iGoalRows_Count, int * const bIsInfeasible)
{
  int i, j, iStatus, nCols;
  double dObjVal, dZero = 0.0;
  SlackPair sp = NULL;
  int sp_count = 0;
  int bWriteGoalProbs = 0;

  /* Ensure the problem is in the original state */
  CHECKED_RETURN( XPRSpostsolve, (prob) )

  /* Zero all costs */
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_COLS, &nCols) )
  for(j = 0; j < nCols; j++) {
    CHECKED_RETURN( XPRSchgobj, (prob, 1, &j, &dZero) )
  }

  /* Add the appropriate slacks for the goals (with associated costs for satisfying those goals) */
  for(i = 0; i < iGoalRows_Count; i++) {
    RelaxConstraint(prob, GoalRows[i].iRow, 1 /*bArchimedianOtherwisePreemptive*/, GoalRows[i].dCost /*dArchimedianWeight*/, &sp, &sp_count);
  }

  if(bWriteGoalProbs) {
    CHECKED_RETURN( XPRSwriteprob, (prob, "goal\\ac_goal", "") )
  }

  /* Solve the LP and get the solve status */
  CHECKED_RETURN( XPRSlpoptimize, (prob, "") )
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_LPSTATUS, &iStatus) )

  /* Exit if the problem is infeasible even with the slacks we have added to the rows */
  if(iStatus != XPRS_LP_OPTIMAL) goto exit_with_infeasible;

  /* Run the MIP search if required */
  if(bRunMip) {
    /* Solve the MIP search and get the solve status */
    CHECKED_RETURN( XPRSmipoptimize, (prob, "") )
    CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_MIPSTATUS, &iStatus) )

    /* Exit if the problem is infeasible even with the slacks we have added to the rows */
    if(iStatus != XPRS_MIP_OPTIMAL) goto exit_with_infeasible;
  }

  *bIsInfeasible = 0;
  if(sp) free(sp); sp = NULL;
  return;
exit_with_infeasible:;
  *bIsInfeasible = 1;
  if(sp) free(sp); sp = NULL;
  return;
}

static void RunGoal_Archimedian_Objective(XPRSprob prob, const int bRunMip, GoalObjective GoalObjs, const int iGoalGoalObjs_Count, int * const bIsInfeasible, double * const dObjRhs_)
{
  int i, j, nRows, nCols, iStatus, ncoeffs;
  double dObjVal;
  int bWriteGoalProbs = 0;
  int mstart[2];
  int *mclind = NULL;
  double *dcmatval = NULL;
  double *dcost = NULL;
  double dObjRhs, dMatRhs;

  /* Ensure the problem is in the original state */
  CHECKED_RETURN( XPRSpostsolve, (prob) )

  /* Setup arrays to store basis and zero all costs */
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_ROWS, &nRows) )
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_COLS, &nCols) )

  if(!(mclind = (int *)malloc(sizeof(int) * nCols))) {
    ERROR_EXIT("Malloc failure")
  }

  if(!(dcmatval = (double *)malloc(sizeof(double) * nCols))) {
    ERROR_EXIT("Malloc failure")
  }

  if(!(dcost = (double *)malloc(sizeof(double) * nCols))) {
    ERROR_EXIT("Malloc failure")
  }

  memset(dcost, 0, sizeof(double) * nCols);

  /* Loop through the goal objectives and sum up the row coefficients into the cost function */
  CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_OBJRHS, &dObjRhs) )
  for(i = 0; i < iGoalGoalObjs_Count; i++) {

    CHECKED_RETURN( XPRSgetrows, (prob, mstart, mclind, dcmatval, nCols, &ncoeffs, GoalObjs[i].iRow, GoalObjs[i].iRow) );

    for(j = 0; j < ncoeffs; j++) {
      dcost[mclind[j]] += dcmatval[j] * GoalObjs[i].dTolerance * GoalObjs[i].iOptimizationSense;
    }

    CHECKED_RETURN( XPRSgetrhs, (prob, &dMatRhs, GoalObjs[i].iRow, GoalObjs[i].iRow) )

    dObjRhs += dMatRhs * GoalObjs[i].dTolerance * GoalObjs[i].iOptimizationSense;

  }

  /* Add the new cost function to the problem */
  for(j = 0; j < nCols; j++) {
    CHECKED_RETURN( XPRSchgobj, (prob, 1, &j, &dcost[j]) )
  }

  if(bWriteGoalProbs) {
    CHECKED_RETURN( XPRSwriteprob, (prob, "goal\\ao_goal", "") )
  }

  if(bRunMip) {
    /* Ensure that we restart the MIP solve each time */
    CHECKED_RETURN( XPRSpostsolve, (prob) )
  }

  /* Solve the LP and get the solve status */
  CHECKED_RETURN( XPRSchgobjsense, (prob,XPRS_OBJ_MINIMIZE) )
  CHECKED_RETURN( XPRSlpoptimize, (prob, "") )

  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_LPSTATUS, &iStatus) )

  /* Exit if the problem is infeasible even with the slacks we have added to the rows */
  if(iStatus != XPRS_LP_OPTIMAL) goto exit_with_infeasible;

  CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_LPOBJVAL, &dObjVal) )

  /* Run the MIP search if required */
  if(bRunMip) {
    /* Solve the MIP search and get the solve status */
    CHECKED_RETURN( XPRSmipoptimize, (prob, "") )
    CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_MIPSTATUS, &iStatus) )

    /* Exit if the problem is infeasible even with the slacks we have added to the rows */
    if(iStatus != XPRS_MIP_OPTIMAL) goto exit_with_infeasible;

    CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_MIPOBJVAL, &dObjVal) )
  }


  if(dObjRhs_) *dObjRhs_ = dObjRhs;
  *bIsInfeasible = 0;
  if(dcost) free(dcost); dcost = NULL;
  if(mclind) free(mclind); mclind = NULL;
  if(dcmatval) free(dcmatval); dcmatval = NULL;
  return;
exit_with_infeasible:;
  if(dObjRhs_) *dObjRhs_ = dObjRhs;
  *bIsInfeasible = 1;
  if(dcost) free(dcost); dcost = NULL;
  if(mclind) free(mclind); mclind = NULL;
  if(dcmatval) free(dcmatval); dcmatval = NULL;
  return;
}

static int Read_Record_GoalObjective(XPRSprob prob, FILE *f, const int bArchimedianOtherwisePreemptive, GoalObjective go, int * const bEof)
{
  char buff[1024], *p;

  *bEof = 0;
  memset(go, -1, sizeof(*go));

  /* Read the row name */
  if(!fgets(buff, sizeof(buff), f)) goto exit_with_eof;
  buff[strlen(buff) - 1] = '\0';
  if(!*buff) goto exit_with_eof;
  CHECKED_RETURN( XPRSgetindex, (prob, 1, buff, &go->iRow) )
  if(go->iRow < 0) {
    goto exit_with_failure;
  }

  if(bArchimedianOtherwisePreemptive) {
    /* Read multiplier */
    if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
    go->dTolerance = strtod(buff, &p); if(!isspace(*p)) goto exit_with_failure;

    /* Read sense */
    if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
    if(strnicmp(buff, "mi", 2) == 0) {
      go->iOptimizationSense = 1;
    } else if(strnicmp(buff, "ma", 2) == 0) {
      go->iOptimizationSense = -1;
    } else {
      goto exit_with_failure;
    }
  } else {
    /* Read sense */
    if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
    if(strnicmp(buff, "mi", 2) == 0) {
      go->iOptimizationSense = 1;
    } else if(strnicmp(buff, "ma", 2) == 0) {
      go->iOptimizationSense = -1;
    } else {
      goto exit_with_failure;
    }

    /* Read multiplier interpretation */
    if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
    if(tolower(*buff) == 'p') {
      go->bFractionIsPercentage = 1;
    } else if(tolower(*buff) == 'd') {
      go->bFractionIsPercentage = 0;
    } else {
      goto exit_with_failure;
    }

    /* Read multiplier */
    if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
    go->dTolerance = strtod(buff, &p); if(!isspace(*p)) goto exit_with_failure;
  }
  return 0;
exit_with_failure:;
  return 1;
exit_with_eof:;
  *bEof = 1;
  return 0;
}

static int Read_Record_GoalConstraint(XPRSprob prob, FILE *f, const int bArchimedianOtherwisePreemptive, GoalConstraint gc, int * const bEof)
{
  char buff[1024], *p;

  *bEof = 0;
  memset(gc, -1, sizeof(*gc));

  /* Read the row name */
  if(!fgets(buff, sizeof(buff), f)) goto exit_with_eof;
  buff[strlen(buff) - 1] = '\0';
  if(!*buff) goto exit_with_eof;
  CHECKED_RETURN( XPRSgetindex, (prob, 1, buff, &gc->iRow) )
  if(gc->iRow < 0) {
    goto exit_with_failure;
  }

  if(bArchimedianOtherwisePreemptive) {
    /* Read multiplier */
    if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
    gc->dCost = strtod(buff, &p); if(!isspace(*p)) goto exit_with_failure;
  }
  return 0;
exit_with_failure:;
  return 1;
 exit_with_eof:;
  *bEof = 1;
  return 0;
}


static int Read_Goal_Directives(XPRSprob prob, const char *sFileName, Goal g)
{
  FILE *f = NULL;
  char buff[1024];
  int bEof;

  memset(g, 0, sizeof(*g));

  if(strlen(sFileName) + strlen(".gol") >= sizeof(buff)) {
    goto exit_with_failure;
  }

  if(strlen(sFileName) < strlen(".gol")) {
    strcpy(buff, sFileName);
    strcat(buff, ".gol");
  } else {
    strcpy(buff, sFileName);
    if(stricmp(buff + strlen(buff) - strlen(".gol"), ".gol")) {
      strcat(buff, ".gol");
    }
  }

  if(!(f = fopen(buff, "r"))) {
    goto exit_with_failure;
  }

  /* Read Archimedian or Preemptive */
  if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
  switch(tolower(buff[0])) {
  case('a') : g->bArchimedianOtherwisePreemptive = 1; break;
  case('p') : g->bArchimedianOtherwisePreemptive = 0; break;
  default : goto exit_with_failure;
  }

  /* Read Constraints or Objective */
  if(!fgets(buff, sizeof(buff), f)) goto exit_with_failure;
  switch(tolower(buff[0])) {
  case('c') : g->bConstraintsOtherwiseObjective = 1; break;
  case('o') : g->bConstraintsOtherwiseObjective = 0; break;
  default : goto exit_with_failure;
  }

  /* Read records to end-of-file */
  for(;;) {
    if(g->bConstraintsOtherwiseObjective) {
      CHECKED_RETURN( GcArray_AddRecord, (&g->gc, &g->gc_count) )
      CHECKED_RETURN( Read_Record_GoalConstraint, (prob, f, g->bArchimedianOtherwisePreemptive, &g->gc[g->gc_count - 1], &bEof) )
      if(bEof) {g->gc_count--; break;}
    } else {
      CHECKED_RETURN( GoArray_AddRecord, (&g->go, &g->go_count) )
      CHECKED_RETURN( Read_Record_GoalObjective, (prob, f, g->bArchimedianOtherwisePreemptive, &g->go[g->go_count - 1], &bEof) )
      if(bEof) {g->go_count--; break;}
    }
  }

  if(f) fclose(f); f = NULL;
  return 0;
exit_with_failure:;
  if(f) fclose(f); f = NULL;
  return 1;
}


void Goal_Run_One(XPRSprob prob, const char * const sGoalFileBaseName, double * const dResult)
{
  int i, bIsInfeasible, iMipEnts, bRunMip;
  struct Goal_s g;
  double dObjVal, dObjRhs;

  /* Read .gol file directives */
  CHECKED_RETURN( Read_Goal_Directives, (prob,  sGoalFileBaseName, &g) )

  /* Decide if we are solving a MIP */
  CHECKED_RETURN( XPRSgetintattrib, (prob, XPRS_MIPENTS, &iMipEnts) )
  bRunMip = !iMipEnts ? 0 : 1;

  /* Run the goal */
  dObjRhs = 0;
  if(g.bConstraintsOtherwiseObjective) {
    if(g.bArchimedianOtherwisePreemptive) {
      RunGoal_Archimedian_Constraint(prob, bRunMip, g.gc, g.gc_count, &bIsInfeasible);
    } else {
      RunGoal_Preemptive_Constraint(prob, bRunMip, g.gc, g.gc_count, &bIsInfeasible);
    }
  } else {
    if(g.bArchimedianOtherwisePreemptive) {
      RunGoal_Archimedian_Objective(prob, bRunMip, g.go, g.go_count, &bIsInfeasible, &dObjRhs);
    } else {
      RunGoal_Preemptive_Objective(prob, bRunMip, g.go, g.go_count, &bIsInfeasible, &dObjRhs);
    }
  }

  /* Free memory allocated in Read_Goal_Directives */
  if(g.go) free(g.go); g.go = NULL;
  if(g.gc) free(g.gc); g.gc = NULL;

  /* Log results */
  CHECKED_RETURN( XPRSgetdblattrib, (prob, XPRS_LPOBJVAL, &dObjVal) )
  dObjVal -= dObjRhs;
  *dResult = dObjVal;
}

int main(void) {
  XPRSprob prob;
  char banner[256];
  double dObjVal;

  CHECKED_RETURN( XPRSinit, ("") );

  CHECKED_RETURN( XPRSgetbanner, (banner) );
  printf("%s\n", banner);

  CHECKED_RETURN( XPRScreateprob, (&prob) );

  CHECKED_RETURN( XPRSsetcbmessage, (prob,Message,NULL) );

  #define DIRECTORY_MATRICES ""
  #define DIRECTORY_GOALFILE ""

  /* Preemptive Objective */
  CHECKED_RETURN( XPRSreadprob, (prob, DIRECTORY_MATRICES "goalobj1","") );
  Goal_Run_One(prob, DIRECTORY_GOALFILE "gc1", &dObjVal);

  /* Archimedian Objective */
  CHECKED_RETURN( XPRSreadprob, (prob, DIRECTORY_MATRICES "goalobj1","") );
  Goal_Run_One(prob, DIRECTORY_GOALFILE "gd1", &dObjVal);

  /* Preemptive Constraint */
  CHECKED_RETURN( XPRSreadprob, (prob, DIRECTORY_MATRICES "goalcon3","") );
  Goal_Run_One(prob, DIRECTORY_GOALFILE "ga3", &dObjVal);

  /* Archimedian Constraint */
  CHECKED_RETURN( XPRSreadprob, (prob, DIRECTORY_MATRICES "goalcon3","") );
  Goal_Run_One(prob, DIRECTORY_GOALFILE "gb3", &dObjVal);

  XPRSdestroyprob(prob);
  XPRSfree();

  return 0;
}



Back to examples browserPrevious example