/*********************************************************************** 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 : -1); 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; 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 */ 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; 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[XPRS_MAXBANNERLENGTH]; 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 "" CHECKED_RETURN( XPRSsetintcontrol, (prob, XPRS_KEEPNROWS, 1) ); /* 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; }