#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include "commonlib.h"
#include "lp_lib.h"
#include "lp_scale.h"
#include "lp_report.h"
#include "lp_MPS.h"
#ifdef FORTIFY
# include "lp_fortify.h"
#endif
# if defined _MSC_VER
# define vsnprintf _vsnprintf
# endif
STATIC void namecpy(char *into, char *from)
{
int i;
for(i = 0; (from[i] != '\0') && (from[i] != '\n') && (from[i] != '\r') && (i < 8); i++)
into[i] = from[i];
into[i] = '\0';
for(i--; (i >= 0) && (into[i] == ' '); i--)
into[i] = '\0';
}
STATIC int scan_lineFIXED(lprec *lp, int section, char* line, char *field1, char *field2, char *field3,
double *field4, char *field5, double *field6)
{
int items = 0, line_len;
char buf[16], *ptr1, *ptr2;
line_len = (int) strlen(line);
while ((line_len) && ((line[line_len-1] == '\n') || (line[line_len-1] == '\r') || (line[line_len-1] == ' ')))
line_len--;
if(line_len >= 1) {
strncpy(buf, line, 4);
buf[4] = '\0';
sscanf(buf, "%s", field1);
items++;
}
else
field1[0] = '\0';
line += 4;
if(line_len >= 5) {
if (line[-1] != ' ') {
report(lp, IMPORTANT, "MPS_readfile: invalid data card; column 4 must be blank\n");
return(-1);
}
namecpy(field2, line);
items++;
}
else
field2[0] = '\0';
line += 10;
if(line_len >= 14) {
if (line[-1] != ' ' || line[-2] != ' ') {
report(lp, IMPORTANT, "MPS_readfile: invalid data card; columns 13-14 must be blank\n");
return(-1);
}
namecpy(field3, line);
items++;
}
else
field3[0] = '\0';
line += 10;
if(line_len >= 25) {
if (line[-1] != ' ' || line[-2] != ' ') {
report(lp, IMPORTANT, "MPS_readfile: invalid data card; columns 23-24 must be blank\n");
return(-1);
}
strncpy(buf, line, 15);
buf[15] = '\0';
for(ptr1 = ptr2 = buf; ; ptr1++)
if(!isspace((unsigned char) *ptr1))
if((*(ptr2++) = *ptr1) == 0)
break;
*field4 = strtod(buf, &ptr1);
if(*ptr1) {
report(lp, IMPORTANT, "MPS_readfile: invalid number in columns 25-36 \n");
return(-1);
}
items++;
}
else
*field4 = 0;
line += 15;
if(line_len >= 40) {
if (line[-1] != ' ' || line[-2] != ' ' || line[-3] != ' ') {
report(lp, IMPORTANT, "MPS_readfile: invalid data card; columns 37-39 must be blank\n");
return(-1);
}
namecpy(field5, line);
items++;
}
else
field5[0] = '\0';
line += 10;
if(line_len >= 50) {
if (line[-1] != ' ' || line[-2] != ' ') {
report(lp, IMPORTANT, "MPS_readfile: invalid data card; columns 48-49 must be blank\n");
return(-1);
}
strncpy(buf, line, 15);
buf[15] = '\0';
for(ptr1 = ptr2 = buf; ; ptr1++)
if(!isspace((unsigned char) *ptr1))
if((*(ptr2++) = *ptr1) == 0)
break;
*field6 = strtod(buf, &ptr1);
if(*ptr1) {
report(lp, IMPORTANT, "MPS_readfile: invalid number in columns 50-61 \n");
return(-1);
}
items++;
}
else
*field6 = 0;
return(items);
}
STATIC int spaces(char *line, int line_len)
{
int l;
char *line1 = line;
while (*line1 == ' ')
line1++;
l = (int) (line1 - line);
if (line_len < l)
l = line_len;
return(l);
}
STATIC int lenfield(char *line, int line_len)
{
int l;
char *line1 = line;
while ((*line1) && (*line1 != ' '))
line1++;
l = (int) (line1 - line);
if (line_len < l)
l = line_len;
return(l);
}
STATIC int scan_lineFREE(lprec *lp, int section, char* line, char *field1, char *field2, char *field3,
double *field4, char *field5, double *field6)
{
int items = 0, line_len, len;
char buf[256], *ptr1 = NULL, *ptr2;
line_len = (int) strlen(line);
while ((line_len) && ((line[line_len-1] == '\n') || (line[line_len-1] == '\r') || (line[line_len-1] == ' ')))
line_len--;
len = spaces(line, line_len);
line += len;
line_len -= len;
if ((section == MPSCOLUMNS) || (section == MPSRHS) || (section == MPSRANGES)) {
field1[0] = '\0';
items++;
}
else {
len = lenfield(line, line_len);
if(line_len >= 1) {
strncpy(buf, line, len);
buf[len] = '\0';
sscanf(buf, "%s", field1);
if(section == MPSBOUNDS) {
for(ptr1 = field1; *ptr1; ptr1++)
*ptr1=(char)toupper(*ptr1);
}
items++;
}
else
field1[0] = '\0';
line += len;
line_len -= len;
len = spaces(line, line_len);
line += len;
line_len -= len;
}
len = lenfield(line, line_len);
if(line_len >= 1) {
strncpy(field2, line, len);
field2[len] = '\0';
items++;
}
else
field2[0] = '\0';
line += len;
line_len -= len;
len = spaces(line, line_len);
line += len;
line_len -= len;
len = lenfield(line, line_len);
if(line_len >= 1) {
strncpy(field3, line, len);
field3[len] = '\0';
items++;
}
else
field3[0] = '\0';
line += len;
line_len -= len;
len = spaces(line, line_len);
line += len;
line_len -= len;
if (*field3) {
if((section == MPSCOLUMNS) && (strcmp(field3, "'MARKER'") == 0)) {
*field4 = 0;
items++;
ptr1 = field3;
}
else if((section == MPSBOUNDS) &&
((strcmp(field1, "FR") == 0) || (strcmp(field1, "MI") == 0) || (strcmp(field1, "PL") == 0) || (strcmp(field1, "BV") == 0)))
;
else {
char *line1 = line;
int line_len1 = line_len;
int items1 = 0;
while (line_len1 > 0) {
len = lenfield(line1, line_len1);
if (len > 0) {
line1 += len;
line_len1 -= len;
items1++;
}
len = spaces(line1, line_len1);
line1 += len;
line_len1 -= len;
}
if ((items1 % 2) == 0) {
*field4 = strtod(field3, &ptr1);
if(*ptr1 == 0) {
strcpy(field3, field2);
if ((section == MPSROWS) || (section == MPSBOUNDS) )
*field2 = 0;
else {
strcpy(field2, field1);
*field1 = 0;
}
items++;
}
else
ptr1 = NULL;
}
else
ptr1 = NULL;
}
}
else {
ptr1 = NULL;
if((section == MPSBOUNDS) &&
((strcmp(field1, "FR") == 0) || (strcmp(field1, "MI") == 0) || (strcmp(field1, "PL") == 0) || (strcmp(field1, "BV") == 0))) {
strcpy(field3, field2);
*field2 = 0;
items++;
}
}
if(ptr1 == NULL) {
len = lenfield(line, line_len);
if(line_len >= 1) {
strncpy(buf, line, len);
buf[len] = '\0';
for(ptr1 = ptr2 = buf; ; ptr1++)
if(!isspace((unsigned char) *ptr1))
if((*(ptr2++) = *ptr1) == 0)
break;
*field4 = strtod(buf, &ptr1);
if(*ptr1)
return(-1);
items++;
}
else
*field4 = 0;
line += len;
line_len -= len;
len = spaces(line, line_len);
line += len;
line_len -= len;
}
len = lenfield(line, line_len);
if(line_len >= 1) {
strncpy(field5, line, len);
field5[len] = '\0';
items++;
}
else
field5[0] = '\0';
line += len;
line_len -= len;
len = spaces(line, line_len);
line += len;
line_len -= len;
len = lenfield(line, line_len);
if(line_len >= 1) {
strncpy(buf, line, len);
buf[len] = '\0';
for(ptr1 = ptr2 = buf; ; ptr1++)
if(!isspace((unsigned char) *ptr1))
if((*(ptr2++) = *ptr1) == 0)
break;
*field6 = strtod(buf, &ptr1);
if(*ptr1)
return(-1);
items++;
}
else
*field6 = 0;
if((section == MPSSOS) && (items == 2)) {
strcpy(field3, field2);
strcpy(field2, field1);
*field1 = 0;
}
if((section != MPSOBJNAME) && (section != MPSBOUNDS)) {
for(ptr1 = field1; *ptr1; ptr1++)
*ptr1=(char)toupper(*ptr1);
}
return(items);
}
STATIC int addmpscolumn(lprec *lp, MYBOOL Int_section, int typeMPS, MYBOOL *Column_ready,
int *count, REAL *Last_column, int *Last_columnno, char *Last_col_name)
{
int ok = TRUE;
if (*Column_ready) {
ok = add_columnex(lp, *count, Last_column, Last_columnno);
if (ok) {
ok = set_col_name(lp, lp->columns, Last_col_name);
}
if (ok) {
set_int(lp, lp->columns, Int_section);
if ((Int_section) && (typeMPS & MPSIBM))
set_bounds(lp, lp->columns, 10.0 / DEF_INFINITE, DEF_INFINITE / 10.0);
}
}
*Column_ready = FALSE;
*count = 0;
return(ok);
}
#if 0#endif
STATIC MYBOOL appendmpsitem(int *count, int rowIndex[], REAL rowValue[])
{
int i = *count;
if(rowIndex[i] < 0)
return( FALSE );
while((i > 0) && (rowIndex[i] < rowIndex[i-1])) {
swapINT (rowIndex+i, rowIndex+i-1);
swapREAL(rowValue+i, rowValue+i-1);
i--;
}
if((i < *count) && (rowIndex[i] == rowIndex[i+1])) {
int ii = i + 1;
rowValue[i] += rowValue[ii];
(*count)--;
while(ii < *count) {
rowIndex[ii] = rowIndex[ii+1];
rowValue[ii] = rowValue[ii+1];
ii++;
}
}
(*count)++;
return( TRUE );
}
MYBOOL MPS_readfile(lprec **newlp, char *filename, int typeMPS, int verbose)
{
MYBOOL status = FALSE;
FILE *fpin;
fpin = fopen(filename, "r");
if(fpin != NULL) {
status = MPS_readhandle(newlp, fpin, typeMPS, verbose);
fclose(fpin);
}
return( status );
}
static int __WINAPI MPS_input(void *fpin, char *buf, int max_size)
{
return(fgets(buf, max_size, (FILE *) fpin) != NULL);
}
MYBOOL __WINAPI MPS_readhandle(lprec **newlp, FILE *filehandle, int typeMPS, int verbose)
{
return(MPS_readex(newlp, (void *) filehandle, MPS_input, typeMPS, verbose));
}
MYBOOL __WINAPI MPS_readex(lprec **newlp, void *userhandle, read_modeldata_func read_modeldata, int typeMPS, int verbose)
{
char field1[BUFSIZ], field2[BUFSIZ], field3[BUFSIZ], field5[BUFSIZ], line[BUFSIZ], tmp[BUFSIZ],
Last_col_name[BUFSIZ], probname[BUFSIZ], OBJNAME[BUFSIZ], *ptr;
int items, row, Lineno, var,
section = MPSUNDEF, variant = 0, NZ = 0, SOS = 0;
MYBOOL Int_section, Column_ready, Column_ready1,
Unconstrained_rows_found = FALSE, OF_found = FALSE, CompleteStatus = FALSE;
double field4, field6;
REAL *Last_column = NULL;
int count = 0, *Last_columnno = NULL;
int OBJSENSE = ROWTYPE_EMPTY;
lprec *lp;
int (*scan_line)(lprec *lp, int section, char* line, char *field1, char *field2, char *field3,
double *field4, char *field5, double *field6);
if(newlp == NULL)
return( CompleteStatus );
else if(*newlp == NULL)
lp = make_lp(0, 0);
else
lp = *newlp;
if((typeMPS & MPSFIXED) == MPSFIXED)
scan_line = scan_lineFIXED;
else if((typeMPS & MPSFREE) == MPSFREE)
scan_line = scan_lineFREE;
else {
report(lp, IMPORTANT, "MPS_readfile: Unrecognized MPS line type.\n");
if (*newlp == NULL)
delete_lp(lp);
return( CompleteStatus );
}
if (lp != NULL) {
lp->source_is_file = TRUE;
lp->verbose = verbose;
strcpy(Last_col_name, "");
strcpy(OBJNAME, "");
Int_section = FALSE;
Column_ready = FALSE;
Lineno = 0;
MEMCLEAR(line, BUFSIZ);
while(read_modeldata(userhandle, line, BUFSIZ - 1)) {
Lineno++;
for(ptr = line; (*ptr) && (isspace((unsigned char) *ptr)); ptr++);
if((line[0] == '*') || (*ptr == 0) || (*ptr == '\n') || (*ptr == '\r')) {
report(lp, FULL, "Comment on line %d: %s", Lineno, line);
continue;
}
report(lp, FULL, "Line %6d: %s", Lineno, line);
if(line[0] != ' ') {
sscanf(line, "%s", tmp);
if(strcmp(tmp, "NAME") == 0) {
section = MPSNAME;
*probname = 0;
sscanf(line, "NAME %s", probname);
if (!set_lp_name(lp, probname))
break;
}
else if(((typeMPS & MPSFREE) == MPSFREE) && (strcmp(tmp, "OBJSENSE") == 0)) {
section = MPSOBJSENSE;
report(lp, FULL, "Switching to OBJSENSE section\n");
}
else if(((typeMPS & MPSFREE) == MPSFREE) && (strcmp(tmp, "OBJNAME") == 0)) {
section = MPSOBJNAME;
report(lp, FULL, "Switching to OBJNAME section\n");
}
else if(strcmp(tmp, "ROWS") == 0) {
section = MPSROWS;
report(lp, FULL, "Switching to ROWS section\n");
}
else if(strcmp(tmp, "COLUMNS") == 0) {
allocREAL(lp, &Last_column, lp->rows + 1, TRUE);
allocINT(lp, &Last_columnno, lp->rows + 1, TRUE);
count = 0;
if ((Last_column == NULL) || (Last_columnno == NULL))
break;
section = MPSCOLUMNS;
report(lp, FULL, "Switching to COLUMNS section\n");
}
else if(strcmp(tmp, "RHS") == 0) {
if (!addmpscolumn(lp, Int_section, typeMPS, &Column_ready, &count, Last_column, Last_columnno, Last_col_name))
break;
section = MPSRHS;
report(lp, FULL, "Switching to RHS section\n");
}
else if(strcmp(tmp, "BOUNDS") == 0) {
section = MPSBOUNDS;
report(lp, FULL, "Switching to BOUNDS section\n");
}
else if(strcmp(tmp, "RANGES") == 0) {
section = MPSRANGES;
report(lp, FULL, "Switching to RANGES section\n");
}
else if((strcmp(tmp, "SOS") == 0) || (strcmp(tmp, "SETS") == 0)) {
section = MPSSOS;
if(strcmp(tmp, "SOS") == 0)
variant = 0;
else
variant = 1;
report(lp, FULL, "Switching to %s section\n", tmp);
}
else if(strcmp(tmp, "ENDATA") == 0) {
report(lp, FULL, "Finished reading MPS file\n");
CompleteStatus = TRUE;
break;
}
else {
report(lp, IMPORTANT, "Unrecognized MPS line %d: %s\n", Lineno, line);
break;
}
}
else {
items = scan_line(lp, section, line, field1, field2, field3, &field4, field5, &field6);
if(items < 0){
report(lp, IMPORTANT, "Syntax error on line %d: %s\n", Lineno, line);
break;
}
switch(section) {
case MPSNAME:
report(lp, IMPORTANT, "Error, extra line under NAME line\n");
break;
case MPSOBJSENSE:
if(OBJSENSE != ROWTYPE_EMPTY) {
report(lp, IMPORTANT, "Error, extra line under OBJSENSE line\n");
break;
}
if((strcmp(field1, "MAXIMIZE") == 0) || (strcmp(field1, "MAX") == 0)) {
OBJSENSE = ROWTYPE_OFMAX;
set_maxim(lp);
}
else if((strcmp(field1, "MINIMIZE") == 0) || (strcmp(field1, "MIN") == 0)) {
OBJSENSE = ROWTYPE_OFMIN;
set_minim(lp);
}
else {
report(lp, SEVERE, "Unknown OBJSENSE direction '%s' on line %d\n", field1, Lineno);
break;
}
continue;
case MPSOBJNAME:
if(*OBJNAME) {
report(lp, IMPORTANT, "Error, extra line under OBJNAME line\n");
break;
}
strcpy(OBJNAME, field1);
continue;
case MPSROWS:
report(lp, FULL, "Row %5d: %s %s\n", lp->rows + 1, field1, field2);
if(strcmp(field1, "N") == 0) {
if((*OBJNAME) && (strcmp(field2, OBJNAME)))
;
else if(!OF_found) {
if (!set_row_name(lp, 0, field2))
break;
OF_found = TRUE;
}
else if(!Unconstrained_rows_found) {
report(lp, IMPORTANT, "Unconstrained row %s ignored\n", field2);
report(lp, IMPORTANT, "Further messages of this kind will be suppressed\n");
Unconstrained_rows_found = TRUE;
}
}
else if(strcmp(field1, "L") == 0) {
if ((!str_add_constraint(lp, "" ,LE ,0)) || (!set_row_name(lp, lp->rows, field2)))
break;
}
else if(strcmp(field1, "G") == 0) {
if ((!str_add_constraint(lp, "" ,GE ,0)) || (!set_row_name(lp, lp->rows, field2)))
break;
}
else if(strcmp(field1, "E") == 0) {
if ((!str_add_constraint(lp, "",EQ ,0)) || (!set_row_name(lp, lp->rows, field2)))
break;
}
else {
report(lp, SEVERE, "Unknown relation code '%s' on line %d\n", field1, Lineno);
break;
}
continue;
case MPSCOLUMNS:
report(lp, FULL, "Column %4d: %s %s %g %s %g\n",
lp->columns + 1, field2, field3, field4, field5, field6);
if((items == 4) || (items == 5) || (items == 6)) {
if (NZ == 0)
strcpy(Last_col_name, field2);
else if(*field2) {
Column_ready1 = (MYBOOL) (strcmp(field2, Last_col_name) != 0);
if(Column_ready1) {
if (find_var(lp, field2, FALSE) >= 0) {
report(lp, SEVERE, "Variable name (%s) is already used!\n", field2);
break;
}
if(Column_ready) {
if (addmpscolumn(lp, Int_section, typeMPS, &Column_ready, &count, Last_column, Last_columnno, Last_col_name)) {
strcpy(Last_col_name, field2);
NZ = 0;
}
else
break;
}
}
}
if(items == 5) {
if(strcmp(field3, "'MARKER'") != 0)
break;
if(strcmp(field5, "'INTORG'") == 0) {
Int_section = TRUE;
report(lp, FULL, "Switching to integer section\n");
}
else if(strcmp(field5, "'INTEND'") == 0) {
Int_section = FALSE;
report(lp, FULL, "Switching to non-integer section\n");
}
else
report(lp, IMPORTANT, "Unknown marker (ignored) at line %d: %s\n",
Lineno, field5);
}
else if((row = find_row(lp, field3, Unconstrained_rows_found)) >= 0) {
if(row > lp->rows)
report(lp, CRITICAL, "Invalid row %s encountered in the MPS file\n", field3);
Last_columnno[count] = row;
Last_column[count] = (REAL)field4;
if(appendmpsitem(&count, Last_columnno, Last_column)) {
NZ++;
Column_ready = TRUE;
}
}
}
if(items == 6) {
if((row = find_row(lp, field5, Unconstrained_rows_found)) >= 0) {
if(row > lp->rows)
report(lp, CRITICAL, "Invalid row %s encountered in the MPS file\n", field5);
Last_columnno[count] = row;
Last_column[count] = (REAL)field6;
if(appendmpsitem(&count, Last_columnno, Last_column)) {
NZ++;
Column_ready = TRUE;
}
}
}
if((items < 4) || (items > 6)) {
report(lp, CRITICAL, "Wrong number of items (%d) in COLUMNS section (line %d)\n",
items, Lineno);
break;
}
continue;
case MPSRHS:
report(lp, FULL, "RHS line: %s %s %g %s %g\n",
field2, field3, field4, field5, field6);
if((items != 4) && (items != 6)) {
report(lp, CRITICAL, "Wrong number of items (%d) in RHS section line %d\n",
items, Lineno);
break;
}
if((row = find_row(lp, field3, Unconstrained_rows_found)) >= 0) {
if ((row == 0) && ((typeMPS & MPSNEGOBJCONST) == MPSNEGOBJCONST))
field4 = -field4;
set_rh(lp, row, (REAL)field4);
}
if(items == 6) {
if((row = find_row(lp, field5, Unconstrained_rows_found)) >= 0) {
if ((row == 0) && ((typeMPS & MPSNEGOBJCONST) == MPSNEGOBJCONST))
field6 = -field6;
set_rh(lp, row, (REAL)field6);
}
}
continue;
case MPSBOUNDS:
report(lp, FULL, "BOUNDS line: %s %s %s %g\n",
field1, field2, field3, field4);
var = find_var(lp, field3, FALSE);
if(var < 0){
Column_ready = TRUE;
if (!addmpscolumn(lp, FALSE, typeMPS, &Column_ready, &count, Last_column, Last_columnno, field3))
break;
Column_ready = TRUE;
var = find_var(lp, field3, TRUE);
}
if(var < 0) ;
else if(strcmp(field1, "UP") == 0) {
if(!set_upbo(lp, var, field4))
break;
}
else if(strcmp(field1, "SC") == 0) {
if(field4 == 0)
field4 = lp->infinite;
if(!set_upbo(lp, var, field4))
break;
set_semicont(lp, var, TRUE);
}
else if(strcmp(field1, "SI") == 0) {
if(field4 == 0)
field4 = lp->infinite;
if(!set_upbo(lp, var, field4))
break;
set_int(lp, var, TRUE);
set_semicont(lp, var, TRUE);
}
else if(strcmp(field1, "LO") == 0) {
if(!set_lowbo(lp, var, field4))
break;
}
else if(strcmp(field1, "PL") == 0) {
if(!set_upbo(lp, var, lp->infinite))
break;
}
else if(strcmp(field1, "MI") == 0) {
if(!set_lowbo(lp, var, -lp->infinite))
break;
}
else if(strcmp(field1, "FR") == 0) {
set_unbounded(lp, var);
}
else if(strcmp(field1, "FX") == 0) {
if(!set_bounds(lp, var, field4, field4))
break;
}
else if(strcmp(field1, "BV") == 0) {
set_binary(lp, var, TRUE);
}
else if(strcmp(field1, "UI") == 0) {
if(!set_upbo(lp, var, field4))
break;
set_int(lp, var, TRUE);
}
else if(strcmp(field1, "LI") == 0) {
if(!set_lowbo(lp, var, field4))
break;
set_int(lp, var, TRUE);
}
else {
report(lp, CRITICAL, "BOUND type %s on line %d is not supported",
field1, Lineno);
break;
}
continue;
case MPSRANGES:
report(lp, FULL, "RANGES line: %s %s %g %s %g",
field2, field3, field4, field5, field6);
if((items != 4) && (items != 6)) {
report(lp, CRITICAL, "Wrong number of items (%d) in RANGES section line %d",
items, Lineno);
break;
}
if((row = find_row(lp, field3, Unconstrained_rows_found)) >= 0) {
if(fabs(field4) >= lp->infinite) {
report(lp, IMPORTANT,
"Warning, Range for row %s >= infinity (value %g) on line %d, ignored",
field3, field4, Lineno);
}
else if(field4 == 0) {
if(lp->orig_upbo[row] != 0)
set_constr_type(lp, row, EQ);
}
else if(is_chsign(lp, row)) {
lp->orig_upbo[row] = fabs(field4);
}
else if((lp->orig_upbo[row] == 0) && (field4 >= 0)) {
set_constr_type(lp, row, GE);
lp->orig_upbo[row] = field4;
}
else if(lp->orig_upbo[row] == lp->infinite) {
lp->orig_upbo[row] = fabs(field4);
}
else if((lp->orig_upbo[row] == 0) && (field4 < 0)) {
set_constr_type(lp, row, LE);
lp->orig_upbo[row] = my_flipsign(field4);
}
else {
report(lp, IMPORTANT,
"Cannot figure out row type, row = %d, is_chsign = %d, upbo = %g on line %d",
row, is_chsign(lp, row), (double)lp->orig_upbo[row], Lineno);
}
}
if(items == 6) {
if((row = find_row(lp, field5, Unconstrained_rows_found)) >= 0) {
if(fabs(field6) >= lp->infinite) {
report(lp, IMPORTANT,
"Warning, Range for row %s >= infinity (value %g) on line %d, ignored",
field5, field6, Lineno);
}
else if(field6 == 0) {
if(lp->orig_upbo[row] != 0)
set_constr_type(lp, row, EQ);
}
else if(is_chsign(lp, row)) {
lp->orig_upbo[row] = fabs(field6);
}
else if(lp->orig_upbo[row] == 0 && field6 >= 0) {
set_constr_type(lp, row, GE);
lp->orig_upbo[row] = field6;
}
else if(lp->orig_upbo[row] == lp->infinite) {
lp->orig_upbo[row] = fabs(field6);
}
else if((lp->orig_upbo[row] == 0) && (field6 < 0)) {
set_constr_type(lp, row, LE);
lp->orig_upbo[row] = my_flipsign(field6);
}
else {
report(lp, IMPORTANT,
"Cannot figure out row type, row = %d, is_chsign = %d, upbo = %g on line %d",
row, is_chsign(lp,row), (double) lp->orig_upbo[row], Lineno);
}
}
}
continue;
case MPSSOS:
report(lp, FULL, "SOS line: %s %s %g %s %g",
field2, field3, field4, field5, field6);
if((items == 0) || (items > 4)) {
report(lp, IMPORTANT,
"Invalid number of items (%d) in SOS section line %d\n",
items, Lineno);
break;
}
if(strlen(field1) == 0) items--;
if(items == 1 || items == 4) {
row = (int) (field1[1] - '0');
if((row <= 0) || (row > 9)) {
report(lp, IMPORTANT,
"Error: Invalid SOS type %s line %d\n", field1, Lineno);
break;
}
field1[0] = '\0';
if(variant == 0) {
if(strlen(field3) == 0)
sprintf(field3, "SOS_%d", SOS_count(lp) + 1);
}
else {
strcpy(field3, field1);
}
if(items == 4)
SOS = (int) field4;
else
SOS = 1;
SOS = add_SOS(lp, field3, (int) row, SOS, 0, NULL, NULL);
}
else {
char *field = (items == 3) ? field3 : field2 ;
var = find_var(lp, field, FALSE);
if(var < 0){
Column_ready = TRUE;
if (!addmpscolumn(lp, FALSE, typeMPS, &Column_ready, &count, Last_column, Last_columnno, field))
break;
Column_ready = TRUE;
var = find_var(lp, field, TRUE);
}
if((var < 0) || (SOS < 1)) ;
else append_SOSrec(lp->SOS->sos_list[SOS-1], 1, &var, &field4);
}
continue;
}
report(lp, IMPORTANT,
"Error: Cannot handle line %d\n", Lineno);
break;
}
}
if((*OBJNAME) && (!OF_found)) {
report(lp, IMPORTANT,
"Error: Objective function specified by OBJNAME card not found\n");
CompleteStatus = FALSE;
}
if(CompleteStatus == FALSE) {
if (*newlp == NULL)
delete_lp(lp);
}
else {
if (typeMPS & MPSIBM) {
REAL lower, upper;
for (var = 1; var <= lp->columns; var++)
if (is_int(lp, var)) {
lower = get_lowbo(lp, var);
upper = get_upbo(lp, var);
if ((lower == 10.0 / DEF_INFINITE) && (upper == DEF_INFINITE / 10.0))
upper = 1.0;
if (lower == 10.0 / DEF_INFINITE)
lower = 0.0;
if (upper == DEF_INFINITE / 10.0)
upper = lp->infinite;
set_bounds(lp, var, lower, upper);
}
}
*newlp = lp;
}
if(Last_column != NULL)
FREE(Last_column);
if(Last_columnno != NULL)
FREE(Last_columnno);
}
return( CompleteStatus );
}
static void number(char *str,REAL value)
{
char __str[80], *_str;
int i;
_str=__str+2;
if (value>=0.0)
if ((value!=0.0) && ((value>0.99999999e12) || (value<0.0001))) {
int n=15;
do {
n--;
i=sprintf(_str,"%*.*E",n,n-6,(double) value);
if (i>12) {
char *ptr=strchr(_str,'E');
if (ptr!=NULL) {
if (*(++ptr)=='-') ptr++;
while ((i>12) && ((*ptr=='+') || (*ptr=='0'))) {
strcpy(ptr,ptr+1);
i--;
}
}
}
} while (i>12);
}
else if (value>=1.0e10) {
int n=13;
do {
i=sprintf(_str,"%*.0f",--n,(double) value);
} while (i>12);
}
else {
if (((i=sprintf(_str,"%12.10f",(double) value))>12) && (_str[12]>='5')) {
for (i=11;i>=0;i--)
if (_str[i]!='.') {
if (++_str[i]>'9') _str[i]='0';
else break;
}
if (i<0) {
*(--_str)='1';
*(--_str)=' ';
}
}
}
else
if ((value<-0.99999999e11) || (value>-0.0001)) {
int n=15;
do {
n--;
i=sprintf(_str,"%*.*E",n,n-7,(double) value);
if (i>12) {
char *ptr=strchr(_str,'E');
if (ptr!=NULL) {
if (*(++ptr)=='-') ptr++;
while ((i>12) && ((*ptr=='+') || (*ptr=='0'))) {
strcpy(ptr,ptr+1);
i--;
}
}
}
} while (i>12);
}
else if (value<=-1.0e9) {
int n=13;
do {
i=sprintf(_str,"%*.0f",--n,(double) value);
} while (i>12);
}
else
if (((i=sprintf(_str,"%12.9f",(double) value))>12) && (_str[12]>='5')) {
for (i=11;i>=1;i--)
if (_str[i]!='.') {
if (++_str[i]>'9') _str[i]='0';
else break;
}
if (i<1) {
*_str='1';
*(--_str)='-';
*(--_str)=' ';
}
}
strncpy(str,_str,12);
}
static char *formatnumber12(char *numberbuffer, double a)
{
#if 0#else
number(numberbuffer, a);
return(numberbuffer);
#endif
}
STATIC char *MPSnameFIXED(char *name0, char *name)
{
sprintf(name0, "%-8.8s", name);
return(name0);
}
STATIC char *MPSnameFREE(char *name0, char *name)
{
if(strlen(name) < 8)
return(MPSnameFIXED(name0, name));
else
return(name);
}
static void write_data(void *userhandle, write_modeldata_func write_modeldata, char *format, ...)
{
char buff[DEF_STRBUFSIZE+1];
va_list ap;
va_start(ap, format);
vsnprintf(buff, DEF_STRBUFSIZE, format, ap);
va_end(ap);
write_modeldata(userhandle, buff);
}
MYBOOL __WINAPI MPS_writefileex(lprec *lp, int typeMPS, void *userhandle, write_modeldata_func write_modeldata)
{
int i, j, jj, je, k, marker, putheader, ChangeSignObj = FALSE, *idx, *idx1;
MYBOOL ok = TRUE, names_used;
REAL a, *val, *val1;
char * (*MPSname)(char *name0, char *name);
char numberbuffer[15];
char name0[9];
if((typeMPS & MPSFIXED) == MPSFIXED) {
MPSname = MPSnameFIXED;
ChangeSignObj = is_maxim(lp);
}
else if((typeMPS & MPSFREE) == MPSFREE) {
MPSname = MPSnameFREE;
}
else {
report(lp, IMPORTANT, "MPS_writefile: unrecognized MPS name type.\n");
return(FALSE);
}
names_used = lp->names_used;
if((typeMPS & MPSFIXED) == MPSFIXED) {
if(names_used)
for(i = 1; (i <= lp->columns) && (ok); i++)
if((lp->col_name[i] != NULL) && (lp->col_name[i]->name != NULL) && (!is_splitvar(lp, i)) && (strlen(lp->col_name[i]->name) > 8))
for(j = 1; (j < i) && (ok); j++)
if((lp->col_name[j] != NULL) && (lp->col_name[j]->name != NULL) && (!is_splitvar(lp, j)))
if(strncmp(lp->col_name[i]->name, lp->col_name[j]->name, 8) == 0)
ok = FALSE;
}
if(!ok) {
lp->names_used = FALSE;
ok = TRUE;
}
memset(numberbuffer, 0, sizeof(numberbuffer));
marker = 0;
write_data(userhandle, write_modeldata, "*<meta creator='lp_solve v%d.%d'>\n",
(int) MAJORVERSION, (int) MINORVERSION);
write_data(userhandle, write_modeldata, "*<meta rows=%d>\n", lp->rows);
write_data(userhandle, write_modeldata, "*<meta columns=%d>\n", lp->columns);
write_data(userhandle, write_modeldata, "*<meta equalities=%d>\n", lp->equalities);
if(SOS_count(lp) > 0)
write_data(userhandle, write_modeldata, "*<meta SOS=%d>\n", SOS_count(lp));
write_data(userhandle, write_modeldata, "*<meta integers=%d>\n", lp->int_vars);
if(lp->sc_vars > 0)
write_data(userhandle, write_modeldata, "*<meta scvars=%d>\n", lp->sc_vars);
write_data(userhandle, write_modeldata, "*<meta origsense='%s'>\n", (is_maxim(lp) ? "MAX" : "MIN"));
write_data(userhandle, write_modeldata, "*\n");
write_data(userhandle, write_modeldata, "NAME %s\n", MPSname(name0, get_lp_name(lp)));
if(((typeMPS & MPSFREE) == MPSFREE) && (is_maxim(lp)))
write_data(userhandle, write_modeldata, "OBJSENSE\n MAX\n");
write_data(userhandle, write_modeldata, "ROWS\n");
for(i = 0; i <= lp->rows; i++) {
if(i == 0)
write_data(userhandle, write_modeldata, " N ");
else if(lp->orig_upbo[i] != 0) {
if(is_chsign(lp,i))
write_data(userhandle, write_modeldata, " G ");
else
write_data(userhandle, write_modeldata, " L ");
}
else
write_data(userhandle, write_modeldata, " E ");
write_data(userhandle, write_modeldata, "%s\n", MPSname(name0, get_row_name(lp, i)));
}
allocREAL(lp, &val, 1 + lp->rows, TRUE);
allocINT(lp, &idx, 1 + lp->rows, TRUE);
write_data(userhandle, write_modeldata, "COLUMNS\n");
for(i = 1; i <= lp->columns; i++) {
if(!is_splitvar(lp, i)) {
if(is_int(lp,i) && (marker % 2) == 0) {
write_data(userhandle, write_modeldata, " MARK%04d 'MARKER' 'INTORG'\n",
marker);
marker++;
}
if(!is_int(lp,i) && (marker % 2) == 1) {
write_data(userhandle, write_modeldata, " MARK%04d 'MARKER' 'INTEND'\n",
marker);
marker++;
}
je = get_columnex(lp, i, val, idx);
for(k = 1, val1 = val, idx1 = idx, jj = 0; jj < je; jj++) {
k = 1 - k;
j = *(idx1++);
a = *(val1++);
if (k == 0) {
write_data(userhandle, write_modeldata, " %s",
MPSname(name0, get_col_name(lp, i)));
write_data(userhandle, write_modeldata, " %s %s",
MPSname(name0, get_row_name(lp, j)),
formatnumber12(numberbuffer, (double) (a * (j == 0 && ChangeSignObj ? -1 : 1))));
}
else
write_data(userhandle, write_modeldata, " %s %s\n",
MPSname(name0, get_row_name(lp, j)),
formatnumber12(numberbuffer, (double) (a * (j == 0 && ChangeSignObj ? -1 : 1))));
}
if(k == 0)
write_data(userhandle, write_modeldata, "\n");
}
}
if((marker % 2) == 1) {
write_data(userhandle, write_modeldata, " MARK%04d 'MARKER' 'INTEND'\n",
marker);
}
FREE(idx);
FREE(val);
write_data(userhandle, write_modeldata, "RHS\n");
for(k = 1, i = 0; i <= lp->rows; i++) {
a = lp->orig_rhs[i];
if(a) {
a = unscaled_value(lp, a, i);
if ((i == 0) && ((typeMPS & MPSNEGOBJCONST) == MPSNEGOBJCONST))
a = -a;
if((i == 0) || is_chsign(lp, i))
a = my_flipsign(a);
k = 1 - k;
if(k == 0)
write_data(userhandle, write_modeldata, " RHS %s %s",
MPSname(name0, get_row_name(lp, i)),
formatnumber12(numberbuffer, (double)a));
else
write_data(userhandle, write_modeldata, " %s %s\n",
MPSname(name0, get_row_name(lp, i)),
formatnumber12(numberbuffer, (double)a));
}
}
if(k == 0)
write_data(userhandle, write_modeldata, "\n");
putheader = TRUE;
for(k = 1, i = 1; i <= lp->rows; i++){
a = 0;
if((lp->orig_upbo[i] < lp->infinite) && (lp->orig_upbo[i] != 0.0))
a = lp->orig_upbo[i];
if(a) {
if(putheader) {
write_data(userhandle, write_modeldata, "RANGES\n");
putheader = FALSE;
}
a = unscaled_value(lp, a, i);
k = 1 - k;
if(k == 0)
write_data(userhandle, write_modeldata, " RGS %s %s",
MPSname(name0, get_row_name(lp, i)),
formatnumber12(numberbuffer, (double)a));
else
write_data(userhandle, write_modeldata, " %s %s\n",
MPSname(name0, get_row_name(lp, i)),
formatnumber12(numberbuffer, (double)a));
}
}
if(k == 0)
write_data(userhandle, write_modeldata, "\n");
putheader = TRUE;
for(i = lp->rows + 1; i <= lp->sum; i++)
if(!is_splitvar(lp, i - lp->rows)) {
j = i - lp->rows;
if((lp->orig_lowbo[i] != 0) && (lp->orig_upbo[i] < lp->infinite) &&
(lp->orig_lowbo[i] == lp->orig_upbo[i])) {
a = lp->orig_upbo[i];
a = unscaled_value(lp, a, i);
if(putheader) {
write_data(userhandle, write_modeldata, "BOUNDS\n");
putheader = FALSE;
}
write_data(userhandle, write_modeldata, " FX BND %s %s\n",
MPSname(name0, get_col_name(lp, j)),
formatnumber12(numberbuffer, (double)a));
}
else if(is_binary(lp, j)) {
if(putheader) {
write_data(userhandle, write_modeldata, "BOUNDS\n");
putheader = FALSE;
}
write_data(userhandle, write_modeldata, " BV BND %s\n",
MPSname(name0, get_col_name(lp, j)));
}
else if(is_unbounded(lp, j)) {
if(putheader) {
write_data(userhandle, write_modeldata, "BOUNDS\n");
putheader = FALSE;
}
write_data(userhandle, write_modeldata, " FR BND %s\n",
MPSname(name0, get_col_name(lp, j)));
}
else {
if((lp->orig_lowbo[i] != 0) || (is_int(lp, j))) {
a = lp->orig_lowbo[i];
a = unscaled_value(lp, a, i);
if(putheader) {
write_data(userhandle, write_modeldata, "BOUNDS\n");
putheader = FALSE;
}
if(lp->orig_lowbo[i] != -lp->infinite)
write_data(userhandle, write_modeldata, " LO BND %s %s\n",
MPSname(name0, get_col_name(lp, j)),
formatnumber12(numberbuffer, (double)a));
else
write_data(userhandle, write_modeldata, " MI BND %s\n",
MPSname(name0, get_col_name(lp, j)));
}
if((lp->orig_upbo[i] < lp->infinite) || (is_semicont(lp, j))) {
a = lp->orig_upbo[i];
if(a < lp->infinite)
a = unscaled_value(lp, a, i);
if(putheader) {
write_data(userhandle, write_modeldata, "BOUNDS\n");
putheader = FALSE;
}
if(is_semicont(lp, j)) {
if(is_int(lp, j))
write_data(userhandle, write_modeldata, " SI BND %s %s\n",
MPSname(name0, get_col_name(lp, j)),
(a < lp->infinite) ? formatnumber12(numberbuffer, (double)a) : " ");
else
write_data(userhandle, write_modeldata, " SC BND %s %s\n",
MPSname(name0, get_col_name(lp, j)),
(a < lp->infinite) ? formatnumber12(numberbuffer, (double)a) : " ");
}
else
write_data(userhandle, write_modeldata, " UP BND %s %s\n",
MPSname(name0, get_col_name(lp, j)),
formatnumber12(numberbuffer, (double)a));
}
}
}
putheader = TRUE;
for(i = 0; i < SOS_count(lp); i++) {
SOSgroup *SOS = lp->SOS;
if(putheader) {
write_data(userhandle, write_modeldata, "SOS\n");
putheader = FALSE;
}
write_data(userhandle, write_modeldata, " S%1d SOS %s %s\n",
SOS->sos_list[i]->type,
MPSname(name0, SOS->sos_list[i]->name),
formatnumber12(numberbuffer, (double) SOS->sos_list[i]->priority));
for(j = 1; j <= SOS->sos_list[i]->size; j++) {
write_data(userhandle, write_modeldata, " SOS %s %s\n",
MPSname(name0, get_col_name(lp, SOS->sos_list[i]->members[j])),
formatnumber12(numberbuffer, (double) SOS->sos_list[i]->weights[j]));
}
}
write_data(userhandle, write_modeldata, "ENDATA\n");
lp->names_used = names_used;
return(ok);
}
static int __WINAPI write_lpdata(void *userhandle, char *buf)
{
fputs(buf, (FILE *) userhandle);
return(TRUE);
}
MYBOOL MPS_writefile(lprec *lp, int typeMPS, char *filename)
{
FILE *output = stdout;
MYBOOL ok;
if (filename != NULL) {
ok = ((output = fopen(filename, "w")) != NULL);
if(!ok)
return(ok);
}
else
output = lp->outstream;
ok = MPS_writefileex(lp, typeMPS, (void *) output, write_lpdata);
if (filename != NULL)
fclose(output);
return(ok);
}
MYBOOL MPS_writehandle(lprec *lp, int typeMPS, FILE *output)
{
MYBOOL ok;
if (output != NULL)
set_outputstream(lp, output);
output = lp->outstream;
ok = MPS_writefileex(lp, typeMPS, (void *) output, write_lpdata);
return(ok);
}
#ifdef OldNameMatch
static int MPS_getnameidx(lprec *lp, char *varname, MYBOOL isrow)
{
int in = -1;
in = get_nameindex(lp, varname, isrow);
if((in < 0) && (strncmp(varname, (isrow ? ROWNAMEMASK : COLNAMEMASK), 1) == 0)) {
if(sscanf(varname + 1, "%d", &in) != 1)
in = -1;
}
return( in );
}
#else
static int MPS_getnameidx(lprec *lp, char *varname, MYBOOL tryrowfirst)
{
int in = -1;
if(lp->names_used) {
in = get_nameindex(lp, varname, tryrowfirst);
if((in > 0) && !tryrowfirst)
in += lp->rows;
else if(in < 0) {
in = get_nameindex(lp, varname, (MYBOOL) !tryrowfirst);
if((in > 0) && tryrowfirst)
in += lp->rows;
}
}
if(in == -1) {
if(strncmp(varname, (tryrowfirst ? ROWNAMEMASK : COLNAMEMASK), 1) == 0) {
if((sscanf(varname + 1, "%d", &in) != 1) ||
(in < (tryrowfirst ? 0 : 1)) || (in > (tryrowfirst ? lp->rows : lp->columns)))
in = -1;
}
else if(strncmp(varname, (!tryrowfirst ? ROWNAMEMASK : COLNAMEMASK), 1) == 0) {
if((sscanf(varname + 1, "%d", &in) != 1) ||
(in < (tryrowfirst ? 0 : 1)) || (in > (tryrowfirst ? lp->rows : lp->columns)))
in = -1;
}
}
return( in );
}
#endif
MYBOOL MPS_readBAS(lprec *lp, int typeMPS, char *filename, char *info)
{
char field1[BUFSIZ], field2[BUFSIZ], field3[BUFSIZ], field5[BUFSIZ],
line[BUFSIZ], tmp[BUFSIZ], *ptr;
double field4, field6;
int ib, in, items, Lineno = 0;
MYBOOL ok;
FILE *input = stdin;
int (*scan_line)(lprec *lp, int section, char* line, char *field1, char *field2, char *field3,
double *field4, char *field5, double *field6);
if((typeMPS & MPSFIXED) == MPSFIXED)
scan_line = scan_lineFIXED;
else if((typeMPS & MPSFREE) == MPSFREE)
scan_line = scan_lineFREE;
else {
report(lp, IMPORTANT, "MPS_readBAS: unrecognized MPS line type.\n");
return(FALSE);
}
ok = (MYBOOL) ((filename != NULL) && ((input = fopen(filename,"r")) != NULL));
if(!ok)
return(ok);
default_basis(lp);
MEMCLEAR(line, BUFSIZ);
ok = FALSE;
while(fgets(line, BUFSIZ - 1, input)) {
Lineno++;
for(ptr = line; (*ptr) && (isspace((unsigned char) *ptr)); ptr++);
if((line[0] == '*') || (*ptr == 0) || (*ptr == '\n') || (*ptr == '\r')) {
report(lp, FULL, "Comment on line %d: %s", Lineno, line);
continue;
}
report(lp, FULL, "Line %6d: %s", Lineno, line);
if(line[0] != ' ') {
sscanf(line, "%s", tmp);
if(strcmp(tmp, "NAME") == 0) {
if(info != NULL) {
*info = 0;
for(ptr = line + 4; (*ptr) && (isspace((unsigned char) *ptr)); ptr++);
in = (int) strlen(ptr);
while ((in > 0) && ((ptr[in - 1] == '\r') || (ptr[in - 1] == '\n') || isspace(ptr[in - 1])))
in--;
ptr[in] = 0;
strcpy(info, ptr);
}
}
else if(strcmp(tmp, "ENDATA") == 0) {
report(lp, FULL, "Finished reading BAS file\n");
ok = TRUE;
break;
}
else {
report(lp, IMPORTANT, "Unrecognized BAS line %d: %s\n", Lineno, line);
break;
}
}
else {
items = scan_line(lp, MPSBOUNDS, line, field1, field2, field3, &field4, field5, &field6);
if(items < 0){
report(lp, IMPORTANT, "Syntax error on line %d: %s\n", Lineno, line);
break;
}
in = MPS_getnameidx(lp, field2, FALSE);
#ifdef OldNameMatch
if(in < 0)
in = MPS_getnameidx(lp, field2, TRUE);
else
in += lp->rows;
#endif
if(in < 0)
break;
if(field1[0] == 'X') {
ib = in;
in = MPS_getnameidx(lp, field3, FALSE);
#ifdef OldNameMatch
if(in < 0)
in = MPS_getnameidx(lp, field3, TRUE);
else
in += lp->rows;
#endif
if(in < 0)
break;
lp->is_lower[in] = (MYBOOL) (field1[1] == 'L');
lp->is_basic[ib] = TRUE;
}
else
lp->is_lower[in] = (MYBOOL) (field1[0] == 'L');
lp->is_basic[in] = FALSE;
}
}
ib = 0;
items = lp->sum;
for(in = 1; in <= items; in++)
if(lp->is_basic[in]) {
ib++;
lp->var_basic[ib] = in;
}
fclose(input);
return( ok );
}
MYBOOL MPS_writeBAS(lprec *lp, int typeMPS, char *filename)
{
int ib, in;
MYBOOL ok;
char name1[100], name2[100];
FILE *output = stdout;
char * (*MPSname)(char *name0, char *name);
char name0[9];
if((typeMPS & MPSFIXED) == MPSFIXED)
MPSname = MPSnameFIXED;
else if((typeMPS & MPSFREE) == MPSFREE)
MPSname = MPSnameFREE;
else {
report(lp, IMPORTANT, "MPS_writeBAS: unrecognized MPS name type.\n");
return(FALSE);
}
ok = (MYBOOL) ((filename == NULL) || ((output = fopen(filename,"w")) != NULL));
if(!ok)
return(ok);
if(filename == NULL && lp->outstream != NULL)
output = lp->outstream;
fprintf(output, "NAME %s Rows %d Cols %d Iters %.0f\n",
get_lp_name(lp), lp->rows, lp->columns, (double) get_total_iter(lp));
ib = lp->rows;
in = 0;
while ((ib < lp->sum) || (in < lp->sum)) {
ib++;
while((ib <= lp->sum) && !lp->is_basic[ib])
ib++;
in++;
while((in <= lp->sum) && (lp->is_basic[in] ||
((in > lp->rows) && lp->is_lower[in])))
in++;
if((ib <= lp->sum) && (in <= lp->sum)) {
strcpy(name1, MPSname(name0, (ib <= lp->rows ? get_row_name(lp, ib) :
get_col_name(lp, ib-lp->rows))));
strcpy(name2, MPSname(name0, (in <= lp->rows ? get_row_name(lp, in) :
get_col_name(lp, in-lp->rows))));
fprintf(output, " %2s %s %s\n", (lp->is_lower[in] ? "XL" : "XU"), name1, name2);
}
else if(in <= lp->sum) {
strcpy(name1, MPSname(name0, (in <= lp->rows ? get_row_name(lp, in) :
get_col_name(lp, in-lp->rows))));
fprintf(output, " %2s %s\n", (lp->is_lower[in] ? "LL" : "UL"), name1);
}
}
fprintf(output, "ENDATA\n");
if(filename != NULL)
fclose(output);
return( ok );
}