/*********************************************************************** Xpress Optimizer Examples ========================= file goal_example.c ``````````````````` Demonstrates how to implement traditional goal programming using Xpress. (c) 2017 Fair Isaac Corporation ***********************************************************************/ #include #include #include "xprs.h" #include #include #include #include #if defined(WIN32) || defined(_WIN32) #else #define strcmpi stricmp #define stricmp strcasecmp #define strnicmp strncasecmp #endif /* 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) /* XPRS optimizer message callback */ static 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; } } 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 int AddSlack(XPRSprob prob, int iRow, int iSlackSign, double dSlackCost, int *iNewColIndex) { int returnCode = 0; double obj = dSlackCost, dmatval = (iSlackSign > 0 ? 1 : -1); double bdl = 0.0, bdu = XPRS_PLUSINFINITY; int mrwind = iRow, mstart[] = {0, 1}; /* Slack will go on the end of the column set */ CHECK_RETURN( XPRSgetintattrib(prob, XPRS_COLS, iNewColIndex) ); CHECK_RETURN( XPRSaddcols(prob, 1 /*newcol*/, 1 /*newnz*/, &obj, mstart, &mrwind, &dmatval, &bdl, &bdu) ); cleanup: return returnCode; } static int GcArray_AddRecord(GoalConstraint *gc, int *gc_count) { int returnCode = 0; if(!*gc) { if(!(*gc = malloc(sizeof(**gc) * (*gc_count + 1)))) { perror("malloc"); returnCode = -2; goto cleanup; } } else { GoalConstraint gc_temp; if(!(gc_temp = realloc(*gc, sizeof(**gc) * (*gc_count + 1)))) { perror("realloc"); returnCode = -2; goto cleanup; } *gc = gc_temp; } (*gc_count)++; cleanup: return returnCode; } static int GoArray_AddRecord(GoalObjective *go, int *go_count) { int returnCode = 0; if(!*go) { if(!(*go = malloc(sizeof(**go) * (*go_count + 1)))) { perror("malloc"); returnCode = -2; goto cleanup; } } else { GoalObjective go_temp; if(!(go_temp = realloc(*go, sizeof(**go) * (*go_count + 1)))) { perror("realloc"); returnCode = -2; goto cleanup; } *go = go_temp; } (*go_count)++; cleanup: return returnCode; } static int SpArray_AddRecord(SlackPair *sp, int *sp_count) { int returnCode = 0; if(!*sp) { if(!(*sp = malloc(sizeof(**sp) * (*sp_count + 1)))) { perror("malloc"); returnCode = -2; goto cleanup; } } else { SlackPair sp_temp; if(!(sp_temp = realloc(*sp, sizeof(**sp) * (*sp_count + 1)))) { perror("realloc"); returnCode = -2; goto cleanup; } *sp = sp_temp; } (*sp_count)++; cleanup: return returnCode; } static int RelaxConstraint(XPRSprob prob, int iRow, int bArchimedianOtherwisePreemptive, double dArchimedianWeight, SlackPair *sp, int * sp_count) { int returnCode = 0; char qrtype; double dCost = (bArchimedianOtherwisePreemptive ? dArchimedianWeight : 0.0); SlackPair sp_; CHECK_RETURN( XPRSgetrowtype(prob, &qrtype, iRow, iRow) ); CHECK_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 : fprintf(stderr, "Unexpected row type '%c'\n", qrtype); returnCode = -1; goto cleanup; } cleanup: return returnCode; } static int RunGoal_Preemptive_Constraint(XPRSprob prob, int bRunMip, GoalConstraint GoalRows, int iGoalRows_Count, int *bIsInfeasible) { int returnCode = 0; 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; *bIsInfeasible = 0; /* Ensure the problem is in the original state */ CHECK_RETURN( XPRSpostsolve(prob) ); /* Add the appropriate slacks for the goals */ for(i = 0; i < iGoalRows_Count; i++) { CHECK_RETURN( RelaxConstraint(prob, GoalRows[i].iRow, 0 /*bArchimedianOtherwisePreemptive*/, 0.0 /*dArchimedianWeight*/, &sp, &sp_count) ); } /* Setup arrays to store basis and zero all costs */ CHECK_RETURN( XPRSgetintattrib(prob, XPRS_ROWS, &nRows) ); CHECK_RETURN( XPRSgetintattrib(prob, XPRS_COLS, &nCols) ); if(!(rstatus = malloc(sizeof(*rstatus) * nRows)) || !(cstatus = malloc(sizeof(*cstatus) * nCols))) { perror("malloc"); returnCode = -2; goto cleanup; } for(j = 0; j < nCols; j++) { CHECK_RETURN( XPRSchgobj(prob, 1, &j, &dZero) ); } if(bWriteGoalProbs) { CHECK_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) CHECK_RETURN( XPRSchgobj(prob, 1, &sp[i].iSlack_Neg, &dOne) ); if(sp[i].iSlack_Pos >= 0) CHECK_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 */ CHECK_RETURN( XPRSloadbasis(prob, rstatus, cstatus) ); } if(bWriteGoalProbs) { char buff[256]; sprintf(buff, "goal\\pc_goal%i", i + 1); CHECK_RETURN( XPRSwriteprob(prob, buff, "") ); } /* Solve the LP and get the solve status */ CHECK_RETURN( XPRSmipoptimize(prob, "l") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_LPOBJVAL, &dObjVal) ); if(dObjVal != 0.0) { /* Exit if we can't satisfy the current goal constraint */ *bIsInfeasible = 1; goto cleanup; } /* Update the hot start basis */ if(!bHaveBasis) { CHECK_RETURN( XPRSgetbasis(prob, rstatus, cstatus) ); bHaveBasis = 1; } /* Run the MIP search if required */ if(bRunMip) { /* Solve the MIP search and get the solve status */ CHECK_RETURN( XPRSmipoptimize(prob, "") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_MIPOBJVAL, &dObjVal) ); if(dObjVal != 0.0) { /* Exit if we can't satisfy the current goal constraint */ *bIsInfeasible = 1; goto cleanup; } } /* 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. */ CHECK_RETURN( XPRSpostsolve(prob) ); if(sp[i].iSlack_Neg >= 0) CHECK_RETURN( XPRSchgbounds(prob, 1, &sp[i].iSlack_Neg, &cBoth, &dZero) ); if(sp[i].iSlack_Pos >= 0) CHECK_RETURN( XPRSchgbounds(prob, 1, &sp[i].iSlack_Pos, &cBoth, &dZero) ); } cleanup: free(sp); free(rstatus); free(cstatus); return returnCode; } static int RunGoal_Preemptive_Objective(XPRSprob prob, int bRunMip, GoalObjective GoalObjs, int iGoalGoalObjs_Count, int *bIsInfeasible, double *dObjRhs_) { int returnCode = 0; int i, j, nRows, nCols, iStatus, bHaveBasis, ncoeffs; double dObjVal, dZero = 0.0; int *rstatus = NULL, *cstatus = NULL; int bWriteGoalProbs = 0; int mstart[2]; int *mclind = NULL; double *dcmatval = NULL; double dRhs, dMatRhs, dMatObRhs; *bIsInfeasible = 0; /* Ensure the problem is in the original state */ CHECK_RETURN( XPRSpostsolve(prob) ); /* Setup arrays to store basis and zero all costs */ CHECK_RETURN( XPRSgetintattrib(prob, XPRS_ROWS, &nRows) ); CHECK_RETURN( XPRSgetintattrib(prob, XPRS_COLS, &nCols) ); if(!(rstatus = malloc(sizeof(*rstatus) * nRows)) || !(cstatus = malloc(sizeof(*cstatus) * nCols)) || !(mclind = malloc(sizeof(*mclind) * nCols)) || !(dcmatval = malloc(sizeof(*dcmatval) * nCols))) { perror("malloc"); returnCode = -2; goto cleanup; } if(bWriteGoalProbs) { CHECK_RETURN( XPRSwriteprob(prob, "goal\\po_goal0", "") ); } /* Loop through the goal objectives */ bHaveBasis = 0; for(i = 0; i < iGoalGoalObjs_Count; i++) { CHECK_RETURN( XPRSgetrhs(prob, &dMatRhs, GoalObjs[i].iRow, GoalObjs[i].iRow) ); CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_OBJRHS, &dMatObRhs) ); /* Copy the row coefficients into the objective */ CHECK_RETURN( XPRSgetrows(prob, mstart, mclind, dcmatval, nCols, &ncoeffs, GoalObjs[i].iRow, GoalObjs[i].iRow) ); for(j = 0; j < nCols; j++) { CHECK_RETURN( XPRSchgobj(prob, 1, &j, &dZero) ); } CHECK_RETURN( XPRSchgobj(prob, ncoeffs, mclind, dcmatval) ); if(bHaveBasis) { /* We have a basis from the last goal solve use this to hot start this solve */ CHECK_RETURN( XPRSloadbasis(prob, rstatus, cstatus) ); } if(bRunMip) { /* Ensure that we restart the MIP solve each time */ CHECK_RETURN( XPRSpostsolve(prob) ); } if(bWriteGoalProbs) { char buff[256]; sprintf(buff, "goal\\po_goal%i", i + 1); CHECK_RETURN( XPRSwriteprob(prob, buff, "") ); } /* Solve the LP and get the solve status */ if(GoalObjs[i].iOptimizationSense >= 0) { CHECK_RETURN( XPRSchgobjsense(prob, XPRS_OBJ_MINIMIZE) ); } else { CHECK_RETURN( XPRSchgobjsense(prob, XPRS_OBJ_MAXIMIZE) ); } CHECK_RETURN( XPRSmipoptimize(prob, "l") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_LPOBJVAL, &dObjVal) ); /* Update the hot start basis */ if(!bHaveBasis) { CHECK_RETURN( XPRSgetbasis(prob, rstatus, cstatus) ); bHaveBasis = 1; } /* Run the MIP search if required */ if(bRunMip) { /* Solve the MIP search and get the solve status */ CHECK_RETURN( XPRSmipoptimize(prob, "") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } CHECK_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'; CHECK_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'; CHECK_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; CHECK_RETURN( XPRSchgrhs(prob, 1, &GoalObjs[i].iRow, &dRhs) ); } cleanup: free(rstatus); free(cstatus); free(mclind); free(dcmatval); return returnCode; } static int RunGoal_Archimedian_Constraint(XPRSprob prob, int bRunMip, GoalConstraint GoalRows, int iGoalRows_Count, int *bIsInfeasible) { int returnCode = 0; int i, j, iStatus, nCols; double dZero = 0.0; SlackPair sp = NULL; int sp_count = 0; int bWriteGoalProbs = 0; *bIsInfeasible = 0; /* Ensure the problem is in the original state */ CHECK_RETURN( XPRSpostsolve(prob) ); /* Zero all costs */ CHECK_RETURN( XPRSgetintattrib(prob, XPRS_COLS, &nCols) ); for(j = 0; j < nCols; j++) { CHECK_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++) { CHECK_RETURN( RelaxConstraint(prob, GoalRows[i].iRow, 1 /*bArchimedianOtherwisePreemptive*/, GoalRows[i].dCost /*dArchimedianWeight*/, &sp, &sp_count) ); } if(bWriteGoalProbs) { CHECK_RETURN( XPRSwriteprob(prob, "goal\\ac_goal", "") ); } /* Solve the LP and get the solve status */ CHECK_RETURN( XPRSlpoptimize(prob, "") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } /* Run the MIP search if required */ if(bRunMip) { /* Solve the MIP search and get the solve status */ CHECK_RETURN( XPRSmipoptimize(prob, "") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } } cleanup: free(sp); return returnCode; } static int RunGoal_Archimedian_Objective(XPRSprob prob, int bRunMip, GoalObjective GoalObjs, int iGoalGoalObjs_Count, int *bIsInfeasible, double *dObjRhs_) { int returnCode = 0; 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; *bIsInfeasible = 0; /* Ensure the problem is in the original state */ CHECK_RETURN( XPRSpostsolve(prob) ); /* Setup arrays to store basis and zero all costs */ CHECK_RETURN( XPRSgetintattrib(prob, XPRS_ROWS, &nRows) ); CHECK_RETURN( XPRSgetintattrib(prob, XPRS_COLS, &nCols) ); if(!(mclind = malloc(sizeof(*mclind) * nCols)) || !(dcmatval = malloc(sizeof(*dcmatval) * nCols)) || !(dcost = malloc(sizeof(*dcost) * nCols))) { perror("malloc"); returnCode = -2; goto cleanup; } memset(dcost, 0, sizeof(double) * nCols); /* Loop through the goal objectives and sum up the row coefficients into the cost function */ CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_OBJRHS, &dObjRhs) ); for(i = 0; i < iGoalGoalObjs_Count; i++) { CHECK_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; } CHECK_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++) { CHECK_RETURN( XPRSchgobj(prob, 1, &j, &dcost[j]) ); } if(bWriteGoalProbs) { CHECK_RETURN( XPRSwriteprob(prob, "goal\\ao_goal", "") ); } if(bRunMip) { /* Ensure that we restart the MIP solve each time */ CHECK_RETURN( XPRSpostsolve(prob) ); } /* Solve the LP and get the solve status */ CHECK_RETURN( XPRSchgobjsense(prob, XPRS_OBJ_MINIMIZE) ); CHECK_RETURN( XPRSlpoptimize(prob, "") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_LPOBJVAL, &dObjVal) ); /* Run the MIP search if required */ if(bRunMip) { /* Solve the MIP search and get the solve status */ CHECK_RETURN( XPRSmipoptimize(prob, "") ); CHECK_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) { *bIsInfeasible = 1; goto cleanup; } CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_MIPOBJVAL, &dObjVal) ); } cleanup: if(dObjRhs_) *dObjRhs_ = dObjRhs; free(dcost); free(mclind); free(dcmatval); return returnCode; } static int Read_Record_GoalObjective(XPRSprob prob, FILE *f, int bArchimedianOtherwisePreemptive, GoalObjective go, int *bEof) { int returnCode = 0; char buff[1024], *p; *bEof = 0; memset(go, -1, sizeof(*go)); /* Read the row name */ if(!fgets(buff, sizeof(buff), f)) { *bEof = 1; goto cleanup; } buff[strlen(buff) - 1] = '\0'; if(!*buff) { *bEof = 1; goto cleanup; } CHECK_RETURN( XPRSgetindex(prob, 1, buff, &go->iRow) ); if(go->iRow < 0) { returnCode = -1; goto cleanup; } if(bArchimedianOtherwisePreemptive) { /* Read multiplier */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } go->dTolerance = strtod(buff, &p); if(!isspace(*p)) { returnCode = -1; goto cleanup; } /* Read sense */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } if(strnicmp(buff, "mi", 2) == 0) { go->iOptimizationSense = 1; } else if(strnicmp(buff, "ma", 2) == 0) { go->iOptimizationSense = -1; } else { returnCode = -1; goto cleanup; } } else { /* Read sense */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } if(strnicmp(buff, "mi", 2) == 0) { go->iOptimizationSense = 1; } else if(strnicmp(buff, "ma", 2) == 0) { go->iOptimizationSense = -1; } else { returnCode = -1; goto cleanup; } /* Read multiplier interpretation */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } if(tolower(*buff) == 'p') { go->bFractionIsPercentage = 1; } else if(tolower(*buff) == 'd') { go->bFractionIsPercentage = 0; } else { returnCode = -1; goto cleanup; } /* Read multiplier */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } go->dTolerance = strtod(buff, &p); if(!isspace(*p)) { returnCode = -1; goto cleanup; } } cleanup: return returnCode; } static int Read_Record_GoalConstraint(XPRSprob prob, FILE *f, int bArchimedianOtherwisePreemptive, GoalConstraint gc, int *bEof) { int returnCode = 0; char buff[1024], *p; *bEof = 0; memset(gc, -1, sizeof(*gc)); /* Read the row name */ if(!fgets(buff, sizeof(buff), f)) { *bEof = 1; goto cleanup; } buff[strlen(buff) - 1] = '\0'; if(!*buff) { *bEof = 1; goto cleanup; } CHECK_RETURN( XPRSgetindex(prob, 1, buff, &gc->iRow) ); if(gc->iRow < 0) { returnCode = -1; goto cleanup; } if(bArchimedianOtherwisePreemptive) { /* Read multiplier */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } gc->dCost = strtod(buff, &p); if(!isspace(*p)) { returnCode = -1; goto cleanup; } } cleanup: return returnCode; } static int Read_Goal_Directives(XPRSprob prob, const char *sFileName, Goal g) { int returnCode = 0; FILE *f = NULL; char buff[1024]; int bEof; memset(g, 0, sizeof(*g)); if(strlen(sFileName) + strlen(".gol") >= sizeof(buff)) { returnCode = -1; goto cleanup; } 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"))) { returnCode = -1; goto cleanup; } /* Read Archimedian or Preemptive */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } switch(tolower(buff[0])) { case('a') : g->bArchimedianOtherwisePreemptive = 1; break; case('p') : g->bArchimedianOtherwisePreemptive = 0; break; default : returnCode = -1; goto cleanup; } /* Read Constraints or Objective */ if(!fgets(buff, sizeof(buff), f)) { returnCode = -1; goto cleanup; } switch(tolower(buff[0])) { case('c') : g->bConstraintsOtherwiseObjective = 1; break; case('o') : g->bConstraintsOtherwiseObjective = 0; break; default : returnCode = -1; goto cleanup; } /* Read records to end-of-file */ for(;;) { if(g->bConstraintsOtherwiseObjective) { CHECK_RETURN( GcArray_AddRecord(&g->gc, &g->gc_count) ); CHECK_RETURN( Read_Record_GoalConstraint(prob, f, g->bArchimedianOtherwisePreemptive, &g->gc[g->gc_count - 1], &bEof) ); if(bEof) {g->gc_count--; break;} } else { CHECK_RETURN( GoArray_AddRecord(&g->go, &g->go_count) ); CHECK_RETURN( Read_Record_GoalObjective(prob, f, g->bArchimedianOtherwisePreemptive, &g->go[g->go_count - 1], &bEof) ); if(bEof) {g->go_count--; break;} } } cleanup: if (f) { fclose(f); } return returnCode; } int Goal_Run_One(XPRSprob prob, const char *sGoalFileBaseName, double *dResult) { int returnCode = 0; int bIsInfeasible, iMipEnts, bRunMip; struct Goal_s g = {0}; double dObjVal, dObjRhs; /* Read .gol file directives */ CHECK_RETURN( Read_Goal_Directives(prob, sGoalFileBaseName, &g) ); /* Decide if we are solving a MIP */ CHECK_RETURN( XPRSgetintattrib(prob, XPRS_MIPENTS, &iMipEnts) ); bRunMip = !iMipEnts ? 0 : 1; /* Run the goal */ dObjRhs = 0; if(g.bConstraintsOtherwiseObjective) { if(g.bArchimedianOtherwisePreemptive) { CHECK_RETURN( RunGoal_Archimedian_Constraint(prob, bRunMip, g.gc, g.gc_count, &bIsInfeasible) ); } else { CHECK_RETURN( RunGoal_Preemptive_Constraint(prob, bRunMip, g.gc, g.gc_count, &bIsInfeasible) ); } } else { if(g.bArchimedianOtherwisePreemptive) { CHECK_RETURN( RunGoal_Archimedian_Objective(prob, bRunMip, g.go, g.go_count, &bIsInfeasible, &dObjRhs) ); } else { CHECK_RETURN( RunGoal_Preemptive_Objective(prob, bRunMip, g.go, g.go_count, &bIsInfeasible, &dObjRhs) ); } } /* Log results */ CHECK_RETURN( XPRSgetdblattrib(prob, XPRS_LPOBJVAL, &dObjVal) ); dObjVal -= dObjRhs; *dResult = dObjVal; cleanup: /* Free memory allocated in Read_Goal_Directives */ if (g.go) { free(g.go); } if (g.gc) { free(g.gc); } return returnCode; } int main(void) { int returnCode = 0; XPRSprob prob = NULL; double dObjVal; /* Initialize the optimizer. */ if ( XPRSinit("") != 0 ) { char message[512]; 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) ); #define DIRECTORY_MATRICES "" #define DIRECTORY_GOALFILE "" CHECK_RETURN( XPRSsetintcontrol(prob, XPRS_KEEPNROWS, 1) ); /* Preemptive Objective */ CHECK_RETURN( XPRSreadprob(prob, DIRECTORY_MATRICES "goalobj1","") ); CHECK_RETURN( Goal_Run_One(prob, DIRECTORY_GOALFILE "gc1", &dObjVal) ); /* Archimedian Objective */ CHECK_RETURN( XPRSreadprob(prob, DIRECTORY_MATRICES "goalobj1","") ); CHECK_RETURN( Goal_Run_One(prob, DIRECTORY_GOALFILE "gd1", &dObjVal) ); /* Preemptive Constraint */ CHECK_RETURN( XPRSreadprob(prob, DIRECTORY_MATRICES "goalcon3","") ); CHECK_RETURN( Goal_Run_One(prob, DIRECTORY_GOALFILE "ga3", &dObjVal) ); /* Archimedian Constraint */ CHECK_RETURN( XPRSreadprob(prob, DIRECTORY_MATRICES "goalcon3","") ); CHECK_RETURN( Goal_Run_One(prob, DIRECTORY_GOALFILE "gb3", &dObjVal) ); 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] = {0}; 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). */ XPRSdestroyprob(prob); XPRSfree(); return returnCode; }