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