src/glpmps.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpmps.c (MPS format routines) */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpapi.h"
alpar@1
    26
alpar@1
    27
/***********************************************************************
alpar@1
    28
*  NAME
alpar@1
    29
*
alpar@1
    30
*  glp_init_mpscp - initialize MPS format control parameters
alpar@1
    31
*
alpar@1
    32
*  SYNOPSIS
alpar@1
    33
*
alpar@1
    34
*  void glp_init_mpscp(glp_mpscp *parm);
alpar@1
    35
*
alpar@1
    36
*  DESCRIPTION
alpar@1
    37
*
alpar@1
    38
*  The routine glp_init_mpscp initializes control parameters, which are
alpar@1
    39
*  used by the MPS input/output routines glp_read_mps and glp_write_mps,
alpar@1
    40
*  with default values.
alpar@1
    41
*
alpar@1
    42
*  Default values of the control parameters are stored in the glp_mpscp
alpar@1
    43
*  structure, which the parameter parm points to. */
alpar@1
    44
alpar@1
    45
void glp_init_mpscp(glp_mpscp *parm)
alpar@1
    46
{     parm->blank = '\0';
alpar@1
    47
      parm->obj_name = NULL;
alpar@1
    48
      parm->tol_mps = 1e-12;
alpar@1
    49
      return;
alpar@1
    50
}
alpar@1
    51
alpar@1
    52
static void check_parm(const char *func, const glp_mpscp *parm)
alpar@1
    53
{     /* check control parameters */
alpar@1
    54
      if (!(0x00 <= parm->blank && parm->blank <= 0xFF) ||
alpar@1
    55
          !(parm->blank == '\0' || isprint(parm->blank)))
alpar@1
    56
         xerror("%s: blank = 0x%02X; invalid parameter\n",
alpar@1
    57
            func, parm->blank);
alpar@1
    58
      if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255))
alpar@1
    59
         xerror("%s: obj_name = \"%.12s...\"; parameter too long\n",
alpar@1
    60
            func, parm->obj_name);
alpar@1
    61
      if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0))
alpar@1
    62
         xerror("%s: tol_mps = %g; invalid parameter\n",
alpar@1
    63
            func, parm->tol_mps);
alpar@1
    64
      return;
alpar@1
    65
}
alpar@1
    66
alpar@1
    67
/***********************************************************************
alpar@1
    68
*  NAME
alpar@1
    69
*
alpar@1
    70
*  glp_read_mps - read problem data in MPS format
alpar@1
    71
*
alpar@1
    72
*  SYNOPSIS
alpar@1
    73
*
alpar@1
    74
*  int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
alpar@1
    75
*     const char *fname);
alpar@1
    76
*
alpar@1
    77
*  DESCRIPTION
alpar@1
    78
*
alpar@1
    79
*  The routine glp_read_mps reads problem data in MPS format from a
alpar@1
    80
*  text file.
alpar@1
    81
*
alpar@1
    82
*  The parameter fmt specifies the version of MPS format:
alpar@1
    83
*
alpar@1
    84
*  GLP_MPS_DECK - fixed (ancient) MPS format;
alpar@1
    85
*  GLP_MPS_FILE - free (modern) MPS format.
alpar@1
    86
*
alpar@1
    87
*  The parameter parm is a pointer to the structure glp_mpscp, which
alpar@1
    88
*  specifies control parameters used by the routine. If parm is NULL,
alpar@1
    89
*  the routine uses default settings.
alpar@1
    90
*
alpar@1
    91
*  The character string fname specifies a name of the text file to be
alpar@1
    92
*  read.
alpar@1
    93
*
alpar@1
    94
*  Note that before reading data the current content of the problem
alpar@1
    95
*  object is completely erased with the routine glp_erase_prob.
alpar@1
    96
*
alpar@1
    97
*  RETURNS
alpar@1
    98
*
alpar@1
    99
*  If the operation was successful, the routine glp_read_mps returns
alpar@1
   100
*  zero. Otherwise, it prints an error message and returns non-zero. */
alpar@1
   101
alpar@1
   102
struct csa
alpar@1
   103
{     /* common storage area */
alpar@1
   104
      glp_prob *P;
alpar@1
   105
      /* pointer to problem object */
alpar@1
   106
      int deck;
alpar@1
   107
      /* MPS format (0 - free, 1 - fixed) */
alpar@1
   108
      const glp_mpscp *parm;
alpar@1
   109
      /* pointer to control parameters */
alpar@1
   110
      const char *fname;
alpar@1
   111
      /* name of input MPS file */
alpar@1
   112
      XFILE *fp;
alpar@1
   113
      /* stream assigned to input MPS file */
alpar@1
   114
      jmp_buf jump;
alpar@1
   115
      /* label for go to in case of error */
alpar@1
   116
      int recno;
alpar@1
   117
      /* current record (card) number */
alpar@1
   118
      int recpos;
alpar@1
   119
      /* current record (card) position */
alpar@1
   120
      int c;
alpar@1
   121
      /* current character */
alpar@1
   122
      int fldno;
alpar@1
   123
      /* current field number */
alpar@1
   124
      char field[255+1];
alpar@1
   125
      /* current field content */
alpar@1
   126
      int w80;
alpar@1
   127
      /* warning 'record must not be longer than 80 chars' issued */
alpar@1
   128
      int wef;
alpar@1
   129
      /* warning 'extra fields detected beyond field 6' issued */
alpar@1
   130
      int obj_row;
alpar@1
   131
      /* objective row number */
alpar@1
   132
      void *work1, *work2, *work3;
alpar@1
   133
      /* working arrays */
alpar@1
   134
};
alpar@1
   135
alpar@1
   136
static void error(struct csa *csa, const char *fmt, ...)
alpar@1
   137
{     /* print error message and terminate processing */
alpar@1
   138
      va_list arg;
alpar@1
   139
      xprintf("%s:%d: ", csa->fname, csa->recno);
alpar@1
   140
      va_start(arg, fmt);
alpar@1
   141
      xvprintf(fmt, arg);
alpar@1
   142
      va_end(arg);
alpar@1
   143
      longjmp(csa->jump, 1);
alpar@1
   144
      /* no return */
alpar@1
   145
}
alpar@1
   146
alpar@1
   147
static void warning(struct csa *csa, const char *fmt, ...)
alpar@1
   148
{     /* print warning message and continue processing */
alpar@1
   149
      va_list arg;
alpar@1
   150
      xprintf("%s:%d: warning: ", csa->fname, csa->recno);
alpar@1
   151
      va_start(arg, fmt);
alpar@1
   152
      xvprintf(fmt, arg);
alpar@1
   153
      va_end(arg);
alpar@1
   154
      return;
alpar@1
   155
}
alpar@1
   156
alpar@1
   157
static void read_char(struct csa *csa)
alpar@1
   158
{     /* read next character */
alpar@1
   159
      int c;
alpar@1
   160
      if (csa->c == '\n')
alpar@1
   161
         csa->recno++, csa->recpos = 0;
alpar@1
   162
      csa->recpos++;
alpar@1
   163
read: c = xfgetc(csa->fp);
alpar@1
   164
      if (c < 0)
alpar@1
   165
      {  if (xferror(csa->fp))
alpar@1
   166
            error(csa, "read error - %s\n", xerrmsg());
alpar@1
   167
         else if (csa->c == '\n')
alpar@1
   168
            error(csa, "unexpected end of file\n");
alpar@1
   169
         else
alpar@1
   170
         {  warning(csa, "missing final end of line\n");
alpar@1
   171
            c = '\n';
alpar@1
   172
         }
alpar@1
   173
      }
alpar@1
   174
      else if (c == '\n')
alpar@1
   175
         ;
alpar@1
   176
      else if (csa->c == '\r')
alpar@1
   177
      {  c = '\r';
alpar@1
   178
         goto badc;
alpar@1
   179
      }
alpar@1
   180
      else if (csa->deck && c == '\r')
alpar@1
   181
      {  csa->c = '\r';
alpar@1
   182
         goto read;
alpar@1
   183
      }
alpar@1
   184
      else if (c == ' ')
alpar@1
   185
         ;
alpar@1
   186
      else if (isspace(c))
alpar@1
   187
      {  if (csa->deck)
alpar@1
   188
badc:       error(csa, "in fixed MPS format white-space character 0x%02"
alpar@1
   189
               "X is not allowed\n", c);
alpar@1
   190
         c = ' ';
alpar@1
   191
      }
alpar@1
   192
      else if (iscntrl(c))
alpar@1
   193
         error(csa, "invalid control character 0x%02X\n", c);
alpar@1
   194
      if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1)
alpar@1
   195
      {  warning(csa, "in fixed MPS format record must not be longer th"
alpar@1
   196
            "an 80 characters\n");
alpar@1
   197
         csa->w80++;
alpar@1
   198
      }
alpar@1
   199
      csa->c = c;
alpar@1
   200
      return;
alpar@1
   201
}
alpar@1
   202
alpar@1
   203
static int indicator(struct csa *csa, int name)
alpar@1
   204
{     /* skip comment records and read possible indicator record */
alpar@1
   205
      int ret;
alpar@1
   206
      /* reset current field number */
alpar@1
   207
      csa->fldno = 0;
alpar@1
   208
loop: /* read the very first character of the next record */
alpar@1
   209
      xassert(csa->c == '\n');
alpar@1
   210
      read_char(csa);
alpar@1
   211
      if (csa->c == ' ' || csa->c == '\n')
alpar@1
   212
      {  /* data record */
alpar@1
   213
         ret = 0;
alpar@1
   214
      }
alpar@1
   215
      else if (csa->c == '*')
alpar@1
   216
      {  /* comment record */
alpar@1
   217
         while (csa->c != '\n')
alpar@1
   218
            read_char(csa);
alpar@1
   219
         goto loop;
alpar@1
   220
      }
alpar@1
   221
      else
alpar@1
   222
      {  /* indicator record */
alpar@1
   223
         int len = 0;
alpar@1
   224
         while (csa->c != ' ' && csa->c != '\n' && len < 12)
alpar@1
   225
         {  csa->field[len++] = (char)csa->c;
alpar@1
   226
            read_char(csa);
alpar@1
   227
         }
alpar@1
   228
         csa->field[len] = '\0';
alpar@1
   229
         if (!(strcmp(csa->field, "NAME")    == 0 ||
alpar@1
   230
               strcmp(csa->field, "ROWS")    == 0 ||
alpar@1
   231
               strcmp(csa->field, "COLUMNS") == 0 ||
alpar@1
   232
               strcmp(csa->field, "RHS")     == 0 ||
alpar@1
   233
               strcmp(csa->field, "RANGES")  == 0 ||
alpar@1
   234
               strcmp(csa->field, "BOUNDS")  == 0 ||
alpar@1
   235
               strcmp(csa->field, "ENDATA")  == 0))
alpar@1
   236
            error(csa, "invalid indicator record\n");
alpar@1
   237
         if (!name)
alpar@1
   238
         {  while (csa->c != '\n')
alpar@1
   239
               read_char(csa);
alpar@1
   240
         }
alpar@1
   241
         ret = 1;
alpar@1
   242
      }
alpar@1
   243
      return ret;
alpar@1
   244
}
alpar@1
   245
alpar@1
   246
static void read_field(struct csa *csa)
alpar@1
   247
{     /* read next field of the current data record */
alpar@1
   248
      csa->fldno++;
alpar@1
   249
      if (csa->deck)
alpar@1
   250
      {  /* fixed MPS format */
alpar@1
   251
         int beg, end, pos;
alpar@1
   252
         /* determine predefined field positions */
alpar@1
   253
         if (csa->fldno == 1)
alpar@1
   254
            beg = 2, end = 3;
alpar@1
   255
         else if (csa->fldno == 2)
alpar@1
   256
            beg = 5, end = 12;
alpar@1
   257
         else if (csa->fldno == 3)
alpar@1
   258
            beg = 15, end = 22;
alpar@1
   259
         else if (csa->fldno == 4)
alpar@1
   260
            beg = 25, end = 36;
alpar@1
   261
         else if (csa->fldno == 5)
alpar@1
   262
            beg = 40, end = 47;
alpar@1
   263
         else if (csa->fldno == 6)
alpar@1
   264
            beg = 50, end = 61;
alpar@1
   265
         else
alpar@1
   266
            xassert(csa != csa);
alpar@1
   267
         /* skip blanks preceding the current field */
alpar@1
   268
         if (csa->c != '\n')
alpar@1
   269
         {  pos = csa->recpos;
alpar@1
   270
            while (csa->recpos < beg)
alpar@1
   271
            {  if (csa->c == ' ')
alpar@1
   272
                  ;
alpar@1
   273
               else if (csa->c == '\n')
alpar@1
   274
                  break;
alpar@1
   275
               else
alpar@1
   276
                  error(csa, "in fixed MPS format positions %d-%d must "
alpar@1
   277
                     "be blank\n", pos, beg-1);
alpar@1
   278
               read_char(csa);
alpar@1
   279
            }
alpar@1
   280
         }
alpar@1
   281
         /* skip possible comment beginning in the field 3 or 5 */
alpar@1
   282
         if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$')
alpar@1
   283
         {  while (csa->c != '\n')
alpar@1
   284
               read_char(csa);
alpar@1
   285
         }
alpar@1
   286
         /* read the current field */
alpar@1
   287
         for (pos = beg; pos <= end; pos++)
alpar@1
   288
         {  if (csa->c == '\n') break;
alpar@1
   289
            csa->field[pos-beg] = (char)csa->c;
alpar@1
   290
            read_char(csa);
alpar@1
   291
         }
alpar@1
   292
         csa->field[pos-beg] = '\0';
alpar@1
   293
         strtrim(csa->field);
alpar@1
   294
         /* skip blanks following the last field */
alpar@1
   295
         if (csa->fldno == 6 && csa->c != '\n')
alpar@1
   296
         {  while (csa->recpos <= 72)
alpar@1
   297
            {  if (csa->c == ' ')
alpar@1
   298
                  ;
alpar@1
   299
               else if (csa->c == '\n')
alpar@1
   300
                  break;
alpar@1
   301
               else
alpar@1
   302
                  error(csa, "in fixed MPS format positions 62-72 must "
alpar@1
   303
                     "be blank\n");
alpar@1
   304
               read_char(csa);
alpar@1
   305
            }
alpar@1
   306
            while (csa->c != '\n')
alpar@1
   307
               read_char(csa);
alpar@1
   308
         }
alpar@1
   309
      }
alpar@1
   310
      else
alpar@1
   311
      {  /* free MPS format */
alpar@1
   312
         int len;
alpar@1
   313
         /* skip blanks preceding the current field */
alpar@1
   314
         while (csa->c == ' ')
alpar@1
   315
            read_char(csa);
alpar@1
   316
         /* skip possible comment */
alpar@1
   317
         if (csa->c == '$')
alpar@1
   318
         {  while (csa->c != '\n')
alpar@1
   319
               read_char(csa);
alpar@1
   320
         }
alpar@1
   321
         /* read the current field */
alpar@1
   322
         len = 0;
alpar@1
   323
         while (!(csa->c == ' ' || csa->c == '\n'))
alpar@1
   324
         {  if (len == 255)
alpar@1
   325
               error(csa, "length of field %d exceeds 255 characters\n",
alpar@1
   326
                  csa->fldno++);
alpar@1
   327
            csa->field[len++] = (char)csa->c;
alpar@1
   328
            read_char(csa);
alpar@1
   329
         }
alpar@1
   330
         csa->field[len] = '\0';
alpar@1
   331
         /* skip anything following the last field (any extra fields
alpar@1
   332
            are considered to be comments) */
alpar@1
   333
         if (csa->fldno == 6)
alpar@1
   334
         {  while (csa->c == ' ')
alpar@1
   335
               read_char(csa);
alpar@1
   336
            if (csa->c != '$' && csa->c != '\n' && csa->wef < 1)
alpar@1
   337
            {  warning(csa, "some extra field(s) detected beyond field "
alpar@1
   338
                  "6; field(s) ignored\n");
alpar@1
   339
               csa->wef++;
alpar@1
   340
            }
alpar@1
   341
            while (csa->c != '\n')
alpar@1
   342
               read_char(csa);
alpar@1
   343
         }
alpar@1
   344
      }
alpar@1
   345
      return;
alpar@1
   346
}
alpar@1
   347
alpar@1
   348
static void patch_name(struct csa *csa, char *name)
alpar@1
   349
{     /* process embedded blanks in symbolic name */
alpar@1
   350
      int blank = csa->parm->blank;
alpar@1
   351
      if (blank == '\0')
alpar@1
   352
      {  /* remove emedded blanks */
alpar@1
   353
         strspx(name);
alpar@1
   354
      }
alpar@1
   355
      else
alpar@1
   356
      {  /* replace embedded blanks by specified character */
alpar@1
   357
         for (; *name != '\0'; name++)
alpar@1
   358
            if (*name == ' ') *name = (char)blank;
alpar@1
   359
      }
alpar@1
   360
      return;
alpar@1
   361
}
alpar@1
   362
alpar@1
   363
static double read_number(struct csa *csa)
alpar@1
   364
{     /* read next field and convert it to floating-point number */
alpar@1
   365
      double x;
alpar@1
   366
      char *s;
alpar@1
   367
      /* read next field */
alpar@1
   368
      read_field(csa);
alpar@1
   369
      xassert(csa->fldno == 4 || csa->fldno == 6);
alpar@1
   370
      if (csa->field[0] == '\0')
alpar@1
   371
         error(csa, "missing numeric value in field %d\n", csa->fldno);
alpar@1
   372
      /* skip initial spaces of the field */
alpar@1
   373
      for (s = csa->field; *s == ' '; s++);
alpar@1
   374
      /* perform conversion */
alpar@1
   375
      if (str2num(s, &x) != 0)
alpar@1
   376
         error(csa, "cannot convert `%s' to floating-point number\n",
alpar@1
   377
            s);
alpar@1
   378
      return x;
alpar@1
   379
}
alpar@1
   380
alpar@1
   381
static void skip_field(struct csa *csa)
alpar@1
   382
{     /* read and skip next field (assumed to be blank) */
alpar@1
   383
      read_field(csa);
alpar@1
   384
      if (csa->field[0] != '\0')
alpar@1
   385
         error(csa, "field %d must be blank\n", csa->fldno);
alpar@1
   386
      return;
alpar@1
   387
}
alpar@1
   388
alpar@1
   389
static void read_name(struct csa *csa)
alpar@1
   390
{     /* read NAME indicator record */
alpar@1
   391
      if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0))
alpar@1
   392
         error(csa, "missing NAME indicator record\n");
alpar@1
   393
      /* this indicator record looks like a data record; simulate that
alpar@1
   394
         fields 1 and 2 were read */
alpar@1
   395
      csa->fldno = 2;
alpar@1
   396
      /* field 3: model name */
alpar@1
   397
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   398
      if (csa->field[0] == '\0')
alpar@1
   399
         warning(csa, "missing model name in field 3\n");
alpar@1
   400
      else
alpar@1
   401
         glp_set_prob_name(csa->P, csa->field);
alpar@1
   402
      /* skip anything following field 3 */
alpar@1
   403
      while (csa->c != '\n')
alpar@1
   404
         read_char(csa);
alpar@1
   405
      return;
alpar@1
   406
}
alpar@1
   407
alpar@1
   408
static void read_rows(struct csa *csa)
alpar@1
   409
{     /* read ROWS section */
alpar@1
   410
      int i, type;
alpar@1
   411
loop: if (indicator(csa, 0)) goto done;
alpar@1
   412
      /* field 1: row type */
alpar@1
   413
      read_field(csa), strspx(csa->field);
alpar@1
   414
      if (strcmp(csa->field, "N") == 0)
alpar@1
   415
         type = GLP_FR;
alpar@1
   416
      else if (strcmp(csa->field, "G") == 0)
alpar@1
   417
         type = GLP_LO;
alpar@1
   418
      else if (strcmp(csa->field, "L") == 0)
alpar@1
   419
         type = GLP_UP;
alpar@1
   420
      else if (strcmp(csa->field, "E") == 0)
alpar@1
   421
         type = GLP_FX;
alpar@1
   422
      else if (csa->field[0] == '\0')
alpar@1
   423
         error(csa, "missing row type in field 1\n");
alpar@1
   424
      else
alpar@1
   425
         error(csa, "invalid row type in field 1\n");
alpar@1
   426
      /* field 2: row name */
alpar@1
   427
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   428
      if (csa->field[0] == '\0')
alpar@1
   429
         error(csa, "missing row name in field 2\n");
alpar@1
   430
      if (glp_find_row(csa->P, csa->field) != 0)
alpar@1
   431
         error(csa, "row `%s' multiply specified\n", csa->field);
alpar@1
   432
      i = glp_add_rows(csa->P, 1);
alpar@1
   433
      glp_set_row_name(csa->P, i, csa->field);
alpar@1
   434
      glp_set_row_bnds(csa->P, i, type, 0.0, 0.0);
alpar@1
   435
      /* fields 3, 4, 5, and 6 must be blank */
alpar@1
   436
      skip_field(csa);
alpar@1
   437
      skip_field(csa);
alpar@1
   438
      skip_field(csa);
alpar@1
   439
      skip_field(csa);
alpar@1
   440
      goto loop;
alpar@1
   441
done: return;
alpar@1
   442
}
alpar@1
   443
alpar@1
   444
static void read_columns(struct csa *csa)
alpar@1
   445
{     /* read COLUMNS section */
alpar@1
   446
      int i, j, f, len, kind = GLP_CV, *ind;
alpar@1
   447
      double aij, *val;
alpar@1
   448
      char name[255+1], *flag;
alpar@1
   449
      /* allocate working arrays */
alpar@1
   450
      csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int));
alpar@1
   451
      csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double));
alpar@1
   452
      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
alpar@1
   453
      memset(&flag[1], 0, csa->P->m);
alpar@1
   454
      /* no current column exists */
alpar@1
   455
      j = 0, len = 0;
alpar@1
   456
loop: if (indicator(csa, 0)) goto done;
alpar@1
   457
      /* field 1 must be blank */
alpar@1
   458
      if (csa->deck)
alpar@1
   459
      {  read_field(csa);
alpar@1
   460
         if (csa->field[0] != '\0')
alpar@1
   461
            error(csa, "field 1 must be blank\n");
alpar@1
   462
      }
alpar@1
   463
      else
alpar@1
   464
         csa->fldno++;
alpar@1
   465
      /* field 2: column or kind name */
alpar@1
   466
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   467
      strcpy(name, csa->field);
alpar@1
   468
      /* field 3: row name or keyword 'MARKER' */
alpar@1
   469
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   470
      if (strcmp(csa->field, "'MARKER'") == 0)
alpar@1
   471
      {  /* process kind data record */
alpar@1
   472
         /* field 4 must be blank */
alpar@1
   473
         if (csa->deck)
alpar@1
   474
         {  read_field(csa);
alpar@1
   475
            if (csa->field[0] != '\0')
alpar@1
   476
               error(csa, "field 4 must be blank\n");
alpar@1
   477
         }
alpar@1
   478
         else
alpar@1
   479
            csa->fldno++;
alpar@1
   480
         /* field 5: keyword 'INTORG' or 'INTEND' */
alpar@1
   481
         read_field(csa), patch_name(csa, csa->field);
alpar@1
   482
         if (strcmp(csa->field, "'INTORG'") == 0)
alpar@1
   483
            kind = GLP_IV;
alpar@1
   484
         else if (strcmp(csa->field, "'INTEND'") == 0)
alpar@1
   485
            kind = GLP_CV;
alpar@1
   486
         else if (csa->field[0] == '\0')
alpar@1
   487
            error(csa, "missing keyword in field 5\n");
alpar@1
   488
         else
alpar@1
   489
            error(csa, "invalid keyword in field 5\n");
alpar@1
   490
         /* field 6 must be blank */
alpar@1
   491
         skip_field(csa);
alpar@1
   492
         goto loop;
alpar@1
   493
      }
alpar@1
   494
      /* process column name specified in field 2 */
alpar@1
   495
      if (name[0] == '\0')
alpar@1
   496
      {  /* the same column as in previous data record */
alpar@1
   497
         if (j == 0)
alpar@1
   498
            error(csa, "missing column name in field 2\n");
alpar@1
   499
      }
alpar@1
   500
      else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0)
alpar@1
   501
      {  /* the same column as in previous data record */
alpar@1
   502
         xassert(j != 0);
alpar@1
   503
      }
alpar@1
   504
      else
alpar@1
   505
      {  /* store the current column */
alpar@1
   506
         if (j != 0)
alpar@1
   507
         {  glp_set_mat_col(csa->P, j, len, ind, val);
alpar@1
   508
            while (len > 0) flag[ind[len--]] = 0;
alpar@1
   509
         }
alpar@1
   510
         /* create new column */
alpar@1
   511
         if (glp_find_col(csa->P, name) != 0)
alpar@1
   512
            error(csa, "column `%s' multiply specified\n", name);
alpar@1
   513
         j = glp_add_cols(csa->P, 1);
alpar@1
   514
         glp_set_col_name(csa->P, j, name);
alpar@1
   515
         glp_set_col_kind(csa->P, j, kind);
alpar@1
   516
         if (kind == GLP_CV)
alpar@1
   517
            glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0);
alpar@1
   518
         else if (kind == GLP_IV)
alpar@1
   519
            glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0);
alpar@1
   520
         else
alpar@1
   521
            xassert(kind != kind);
alpar@1
   522
      }
alpar@1
   523
      /* process fields 3-4 and 5-6 */
alpar@1
   524
      for (f = 3; f <= 5; f += 2)
alpar@1
   525
      {  /* field 3 or 5: row name */
alpar@1
   526
         if (f == 3)
alpar@1
   527
         {  if (csa->field[0] == '\0')
alpar@1
   528
               error(csa, "missing row name in field 3\n");
alpar@1
   529
         }
alpar@1
   530
         else
alpar@1
   531
         {  read_field(csa), patch_name(csa, csa->field);
alpar@1
   532
            if (csa->field[0] == '\0')
alpar@1
   533
            {  /* if field 5 is blank, field 6 also must be blank */
alpar@1
   534
               skip_field(csa);
alpar@1
   535
               continue;
alpar@1
   536
            }
alpar@1
   537
         }
alpar@1
   538
         i = glp_find_row(csa->P, csa->field);
alpar@1
   539
         if (i == 0)
alpar@1
   540
            error(csa, "row `%s' not found\n", csa->field);
alpar@1
   541
         if (flag[i])
alpar@1
   542
            error(csa, "duplicate coefficient in row `%s'\n",
alpar@1
   543
               csa->field);
alpar@1
   544
         /* field 4 or 6: coefficient value */
alpar@1
   545
         aij = read_number(csa);
alpar@1
   546
         if (fabs(aij) < csa->parm->tol_mps) aij = 0.0;
alpar@1
   547
         len++, ind[len] = i, val[len] = aij, flag[i] = 1;
alpar@1
   548
      }
alpar@1
   549
      goto loop;
alpar@1
   550
done: /* store the last column */
alpar@1
   551
      if (j != 0)
alpar@1
   552
         glp_set_mat_col(csa->P, j, len, ind, val);
alpar@1
   553
      /* free working arrays */
alpar@1
   554
      xfree(ind);
alpar@1
   555
      xfree(val);
alpar@1
   556
      xfree(flag);
alpar@1
   557
      csa->work1 = csa->work2 = csa->work3 = NULL;
alpar@1
   558
      return;
alpar@1
   559
}
alpar@1
   560
alpar@1
   561
static void read_rhs(struct csa *csa)
alpar@1
   562
{     /* read RHS section */
alpar@1
   563
      int i, f, v, type;
alpar@1
   564
      double rhs;
alpar@1
   565
      char name[255+1], *flag;
alpar@1
   566
      /* allocate working array */
alpar@1
   567
      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
alpar@1
   568
      memset(&flag[1], 0, csa->P->m);
alpar@1
   569
      /* no current RHS vector exists */
alpar@1
   570
      v = 0;
alpar@1
   571
loop: if (indicator(csa, 0)) goto done;
alpar@1
   572
      /* field 1 must be blank */
alpar@1
   573
      if (csa->deck)
alpar@1
   574
      {  read_field(csa);
alpar@1
   575
         if (csa->field[0] != '\0')
alpar@1
   576
            error(csa, "field 1 must be blank\n");
alpar@1
   577
      }
alpar@1
   578
      else
alpar@1
   579
         csa->fldno++;
alpar@1
   580
      /* field 2: RHS vector name */
alpar@1
   581
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   582
      if (csa->field[0] == '\0')
alpar@1
   583
      {  /* the same RHS vector as in previous data record */
alpar@1
   584
         if (v == 0)
alpar@1
   585
         {  warning(csa, "missing RHS vector name in field 2\n");
alpar@1
   586
            goto blnk;
alpar@1
   587
         }
alpar@1
   588
      }
alpar@1
   589
      else if (v != 0 && strcmp(csa->field, name) == 0)
alpar@1
   590
      {  /* the same RHS vector as in previous data record */
alpar@1
   591
         xassert(v != 0);
alpar@1
   592
      }
alpar@1
   593
      else
alpar@1
   594
blnk: {  /* new RHS vector */
alpar@1
   595
         if (v != 0)
alpar@1
   596
            error(csa, "multiple RHS vectors not supported\n");
alpar@1
   597
         v++;
alpar@1
   598
         strcpy(name, csa->field);
alpar@1
   599
      }
alpar@1
   600
      /* process fields 3-4 and 5-6 */
alpar@1
   601
      for (f = 3; f <= 5; f += 2)
alpar@1
   602
      {  /* field 3 or 5: row name */
alpar@1
   603
         read_field(csa), patch_name(csa, csa->field);
alpar@1
   604
         if (csa->field[0] == '\0')
alpar@1
   605
         {  if (f == 3)
alpar@1
   606
               error(csa, "missing row name in field 3\n");
alpar@1
   607
            else
alpar@1
   608
            {  /* if field 5 is blank, field 6 also must be blank */
alpar@1
   609
               skip_field(csa);
alpar@1
   610
               continue;
alpar@1
   611
            }
alpar@1
   612
         }
alpar@1
   613
         i = glp_find_row(csa->P, csa->field);
alpar@1
   614
         if (i == 0)
alpar@1
   615
            error(csa, "row `%s' not found\n", csa->field);
alpar@1
   616
         if (flag[i])
alpar@1
   617
            error(csa, "duplicate right-hand side for row `%s'\n",
alpar@1
   618
               csa->field);
alpar@1
   619
         /* field 4 or 6: right-hand side value */
alpar@1
   620
         rhs = read_number(csa);
alpar@1
   621
         if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0;
alpar@1
   622
         type = csa->P->row[i]->type;
alpar@1
   623
         if (type == GLP_FR)
alpar@1
   624
         {  if (i == csa->obj_row)
alpar@1
   625
               glp_set_obj_coef(csa->P, 0, rhs);
alpar@1
   626
            else if (rhs != 0.0)
alpar@1
   627
               warning(csa, "non-zero right-hand side for free row `%s'"
alpar@1
   628
                  " ignored\n", csa->P->row[i]->name);
alpar@1
   629
         }
alpar@1
   630
         else
alpar@1
   631
            glp_set_row_bnds(csa->P, i, type, rhs, rhs);
alpar@1
   632
         flag[i] = 1;
alpar@1
   633
      }
alpar@1
   634
      goto loop;
alpar@1
   635
done: /* free working array */
alpar@1
   636
      xfree(flag);
alpar@1
   637
      csa->work3 = NULL;
alpar@1
   638
      return;
alpar@1
   639
}
alpar@1
   640
alpar@1
   641
static void read_ranges(struct csa *csa)
alpar@1
   642
{     /* read RANGES section */
alpar@1
   643
      int i, f, v, type;
alpar@1
   644
      double rhs, rng;
alpar@1
   645
      char name[255+1], *flag;
alpar@1
   646
      /* allocate working array */
alpar@1
   647
      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
alpar@1
   648
      memset(&flag[1], 0, csa->P->m);
alpar@1
   649
      /* no current RANGES vector exists */
alpar@1
   650
      v = 0;
alpar@1
   651
loop: if (indicator(csa, 0)) goto done;
alpar@1
   652
      /* field 1 must be blank */
alpar@1
   653
      if (csa->deck)
alpar@1
   654
      {  read_field(csa);
alpar@1
   655
         if (csa->field[0] != '\0')
alpar@1
   656
            error(csa, "field 1 must be blank\n");
alpar@1
   657
      }
alpar@1
   658
      else
alpar@1
   659
         csa->fldno++;
alpar@1
   660
      /* field 2: RANGES vector name */
alpar@1
   661
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   662
      if (csa->field[0] == '\0')
alpar@1
   663
      {  /* the same RANGES vector as in previous data record */
alpar@1
   664
         if (v == 0)
alpar@1
   665
         {  warning(csa, "missing RANGES vector name in field 2\n");
alpar@1
   666
            goto blnk;
alpar@1
   667
         }
alpar@1
   668
      }
alpar@1
   669
      else if (v != 0 && strcmp(csa->field, name) == 0)
alpar@1
   670
      {  /* the same RANGES vector as in previous data record */
alpar@1
   671
         xassert(v != 0);
alpar@1
   672
      }
alpar@1
   673
      else
alpar@1
   674
blnk: {  /* new RANGES vector */
alpar@1
   675
         if (v != 0)
alpar@1
   676
            error(csa, "multiple RANGES vectors not supported\n");
alpar@1
   677
         v++;
alpar@1
   678
         strcpy(name, csa->field);
alpar@1
   679
      }
alpar@1
   680
      /* process fields 3-4 and 5-6 */
alpar@1
   681
      for (f = 3; f <= 5; f += 2)
alpar@1
   682
      {  /* field 3 or 5: row name */
alpar@1
   683
         read_field(csa), patch_name(csa, csa->field);
alpar@1
   684
         if (csa->field[0] == '\0')
alpar@1
   685
         {  if (f == 3)
alpar@1
   686
               error(csa, "missing row name in field 3\n");
alpar@1
   687
            else
alpar@1
   688
            {  /* if field 5 is blank, field 6 also must be blank */
alpar@1
   689
               skip_field(csa);
alpar@1
   690
               continue;
alpar@1
   691
            }
alpar@1
   692
         }
alpar@1
   693
         i = glp_find_row(csa->P, csa->field);
alpar@1
   694
         if (i == 0)
alpar@1
   695
            error(csa, "row `%s' not found\n", csa->field);
alpar@1
   696
         if (flag[i])
alpar@1
   697
            error(csa, "duplicate range for row `%s'\n", csa->field);
alpar@1
   698
         /* field 4 or 6: range value */
alpar@1
   699
         rng = read_number(csa);
alpar@1
   700
         if (fabs(rng) < csa->parm->tol_mps) rng = 0.0;
alpar@1
   701
         type = csa->P->row[i]->type;
alpar@1
   702
         if (type == GLP_FR)
alpar@1
   703
            warning(csa, "range for free row `%s' ignored\n",
alpar@1
   704
               csa->P->row[i]->name);
alpar@1
   705
         else if (type == GLP_LO)
alpar@1
   706
         {  rhs = csa->P->row[i]->lb;
alpar@1
   707
            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
alpar@1
   708
               rhs, rhs + fabs(rng));
alpar@1
   709
         }
alpar@1
   710
         else if (type == GLP_UP)
alpar@1
   711
         {  rhs = csa->P->row[i]->ub;
alpar@1
   712
            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
alpar@1
   713
               rhs - fabs(rng), rhs);
alpar@1
   714
         }
alpar@1
   715
         else if (type == GLP_FX)
alpar@1
   716
         {  rhs = csa->P->row[i]->lb;
alpar@1
   717
            if (rng > 0.0)
alpar@1
   718
               glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng);
alpar@1
   719
            else if (rng < 0.0)
alpar@1
   720
               glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs);
alpar@1
   721
         }
alpar@1
   722
         else
alpar@1
   723
            xassert(type != type);
alpar@1
   724
         flag[i] = 1;
alpar@1
   725
      }
alpar@1
   726
      goto loop;
alpar@1
   727
done: /* free working array */
alpar@1
   728
      xfree(flag);
alpar@1
   729
      csa->work3 = NULL;
alpar@1
   730
      return;
alpar@1
   731
}
alpar@1
   732
alpar@1
   733
static void read_bounds(struct csa *csa)
alpar@1
   734
{     /* read BOUNDS section */
alpar@1
   735
      GLPCOL *col;
alpar@1
   736
      int j, v, mask, data;
alpar@1
   737
      double bnd, lb, ub;
alpar@1
   738
      char type[2+1], name[255+1], *flag;
alpar@1
   739
      /* allocate working array */
alpar@1
   740
      csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char));
alpar@1
   741
      memset(&flag[1], 0, csa->P->n);
alpar@1
   742
      /* no current BOUNDS vector exists */
alpar@1
   743
      v = 0;
alpar@1
   744
loop: if (indicator(csa, 0)) goto done;
alpar@1
   745
      /* field 1: bound type */
alpar@1
   746
      read_field(csa);
alpar@1
   747
      if (strcmp(csa->field, "LO") == 0)
alpar@1
   748
         mask = 0x01, data = 1;
alpar@1
   749
      else if (strcmp(csa->field, "UP") == 0)
alpar@1
   750
         mask = 0x10, data = 1;
alpar@1
   751
      else if (strcmp(csa->field, "FX") == 0)
alpar@1
   752
         mask = 0x11, data = 1;
alpar@1
   753
      else if (strcmp(csa->field, "FR") == 0)
alpar@1
   754
         mask = 0x11, data = 0;
alpar@1
   755
      else if (strcmp(csa->field, "MI") == 0)
alpar@1
   756
         mask = 0x01, data = 0;
alpar@1
   757
      else if (strcmp(csa->field, "PL") == 0)
alpar@1
   758
         mask = 0x10, data = 0;
alpar@1
   759
      else if (strcmp(csa->field, "LI") == 0)
alpar@1
   760
         mask = 0x01, data = 1;
alpar@1
   761
      else if (strcmp(csa->field, "UI") == 0)
alpar@1
   762
         mask = 0x10, data = 1;
alpar@1
   763
      else if (strcmp(csa->field, "BV") == 0)
alpar@1
   764
         mask = 0x11, data = 0;
alpar@1
   765
      else if (csa->field[0] == '\0')
alpar@1
   766
         error(csa, "missing bound type in field 1\n");
alpar@1
   767
      else
alpar@1
   768
         error(csa, "invalid bound type in field 1\n");
alpar@1
   769
      strcpy(type, csa->field);
alpar@1
   770
      /* field 2: BOUNDS vector name */
alpar@1
   771
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   772
      if (csa->field[0] == '\0')
alpar@1
   773
      {  /* the same BOUNDS vector as in previous data record */
alpar@1
   774
         if (v == 0)
alpar@1
   775
         {  warning(csa, "missing BOUNDS vector name in field 2\n");
alpar@1
   776
            goto blnk;
alpar@1
   777
         }
alpar@1
   778
      }
alpar@1
   779
      else if (v != 0 && strcmp(csa->field, name) == 0)
alpar@1
   780
      {  /* the same BOUNDS vector as in previous data record */
alpar@1
   781
         xassert(v != 0);
alpar@1
   782
      }
alpar@1
   783
      else
alpar@1
   784
blnk: {  /* new BOUNDS vector */
alpar@1
   785
         if (v != 0)
alpar@1
   786
            error(csa, "multiple BOUNDS vectors not supported\n");
alpar@1
   787
         v++;
alpar@1
   788
         strcpy(name, csa->field);
alpar@1
   789
      }
alpar@1
   790
      /* field 3: column name */
alpar@1
   791
      read_field(csa), patch_name(csa, csa->field);
alpar@1
   792
      if (csa->field[0] == '\0')
alpar@1
   793
         error(csa, "missing column name in field 3\n");
alpar@1
   794
      j = glp_find_col(csa->P, csa->field);
alpar@1
   795
      if (j == 0)
alpar@1
   796
         error(csa, "column `%s' not found\n", csa->field);
alpar@1
   797
      if ((flag[j] & mask) == 0x01)
alpar@1
   798
         error(csa, "duplicate lower bound for column `%s'\n",
alpar@1
   799
            csa->field);
alpar@1
   800
      if ((flag[j] & mask) == 0x10)
alpar@1
   801
         error(csa, "duplicate upper bound for column `%s'\n",
alpar@1
   802
            csa->field);
alpar@1
   803
      xassert((flag[j] & mask) == 0x00);
alpar@1
   804
      /* field 4: bound value */
alpar@1
   805
      if (data)
alpar@1
   806
      {  bnd = read_number(csa);
alpar@1
   807
         if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0;
alpar@1
   808
      }
alpar@1
   809
      else
alpar@1
   810
         read_field(csa), bnd = 0.0;
alpar@1
   811
      /* get current column bounds */
alpar@1
   812
      col = csa->P->col[j];
alpar@1
   813
      if (col->type == GLP_FR)
alpar@1
   814
         lb = -DBL_MAX, ub = +DBL_MAX;
alpar@1
   815
      else if (col->type == GLP_LO)
alpar@1
   816
         lb = col->lb, ub = +DBL_MAX;
alpar@1
   817
      else if (col->type == GLP_UP)
alpar@1
   818
         lb = -DBL_MAX, ub = col->ub;
alpar@1
   819
      else if (col->type == GLP_DB)
alpar@1
   820
         lb = col->lb, ub = col->ub;
alpar@1
   821
      else if (col->type == GLP_FX)
alpar@1
   822
         lb = ub = col->lb;
alpar@1
   823
      else
alpar@1
   824
         xassert(col != col);
alpar@1
   825
      /* change column bounds */
alpar@1
   826
      if (strcmp(type, "LO") == 0)
alpar@1
   827
         lb = bnd;
alpar@1
   828
      else if (strcmp(type, "UP") == 0)
alpar@1
   829
         ub = bnd;
alpar@1
   830
      else if (strcmp(type, "FX") == 0)
alpar@1
   831
         lb = ub = bnd;
alpar@1
   832
      else if (strcmp(type, "FR") == 0)
alpar@1
   833
         lb = -DBL_MAX, ub = +DBL_MAX;
alpar@1
   834
      else if (strcmp(type, "MI") == 0)
alpar@1
   835
         lb = -DBL_MAX;
alpar@1
   836
      else if (strcmp(type, "PL") == 0)
alpar@1
   837
         ub = +DBL_MAX;
alpar@1
   838
      else if (strcmp(type, "LI") == 0)
alpar@1
   839
      {  glp_set_col_kind(csa->P, j, GLP_IV);
alpar@1
   840
         lb = ceil(bnd);
alpar@1
   841
      }
alpar@1
   842
      else if (strcmp(type, "UI") == 0)
alpar@1
   843
      {  glp_set_col_kind(csa->P, j, GLP_IV);
alpar@1
   844
         ub = floor(bnd);
alpar@1
   845
      }
alpar@1
   846
      else if (strcmp(type, "BV") == 0)
alpar@1
   847
      {  glp_set_col_kind(csa->P, j, GLP_IV);
alpar@1
   848
         lb = 0.0, ub = 1.0;
alpar@1
   849
      }
alpar@1
   850
      else
alpar@1
   851
         xassert(type != type);
alpar@1
   852
      /* set new column bounds */
alpar@1
   853
      if (lb == -DBL_MAX && ub == +DBL_MAX)
alpar@1
   854
         glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub);
alpar@1
   855
      else if (ub == +DBL_MAX)
alpar@1
   856
         glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub);
alpar@1
   857
      else if (lb == -DBL_MAX)
alpar@1
   858
         glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub);
alpar@1
   859
      else if (lb != ub)
alpar@1
   860
         glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub);
alpar@1
   861
      else
alpar@1
   862
         glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub);
alpar@1
   863
      flag[j] |= (char)mask;
alpar@1
   864
      /* fields 5 and 6 must be blank */
alpar@1
   865
      skip_field(csa);
alpar@1
   866
      skip_field(csa);
alpar@1
   867
      goto loop;
alpar@1
   868
done: /* free working array */
alpar@1
   869
      xfree(flag);
alpar@1
   870
      csa->work3 = NULL;
alpar@1
   871
      return;
alpar@1
   872
}
alpar@1
   873
alpar@1
   874
int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
alpar@1
   875
      const char *fname)
alpar@1
   876
{     /* read problem data in MPS format */
alpar@1
   877
      glp_mpscp _parm;
alpar@1
   878
      struct csa _csa, *csa = &_csa;
alpar@1
   879
      int ret;
alpar@1
   880
      xprintf("Reading problem data from `%s'...\n", fname);
alpar@1
   881
      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
alpar@1
   882
         xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt);
alpar@1
   883
      if (parm == NULL)
alpar@1
   884
         glp_init_mpscp(&_parm), parm = &_parm;
alpar@1
   885
      /* check control parameters */
alpar@1
   886
      check_parm("glp_read_mps", parm);
alpar@1
   887
      /* initialize common storage area */
alpar@1
   888
      csa->P = P;
alpar@1
   889
      csa->deck = (fmt == GLP_MPS_DECK);
alpar@1
   890
      csa->parm = parm;
alpar@1
   891
      csa->fname = fname;
alpar@1
   892
      csa->fp = NULL;
alpar@1
   893
      if (setjmp(csa->jump))
alpar@1
   894
      {  ret = 1;
alpar@1
   895
         goto done;
alpar@1
   896
      }
alpar@1
   897
      csa->recno = csa->recpos = 0;
alpar@1
   898
      csa->c = '\n';
alpar@1
   899
      csa->fldno = 0;
alpar@1
   900
      csa->field[0] = '\0';
alpar@1
   901
      csa->w80 = csa->wef = 0;
alpar@1
   902
      csa->obj_row = 0;
alpar@1
   903
      csa->work1 = csa->work2 = csa->work3 = NULL;
alpar@1
   904
      /* erase problem object */
alpar@1
   905
      glp_erase_prob(P);
alpar@1
   906
      glp_create_index(P);
alpar@1
   907
      /* open input MPS file */
alpar@1
   908
      csa->fp = xfopen(fname, "r");
alpar@1
   909
      if (csa->fp == NULL)
alpar@1
   910
      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
alpar@1
   911
         ret = 1;
alpar@1
   912
         goto done;
alpar@1
   913
      }
alpar@1
   914
      /* read NAME indicator record */
alpar@1
   915
      read_name(csa);
alpar@1
   916
      if (P->name != NULL)
alpar@1
   917
         xprintf("Problem: %s\n", P->name);
alpar@1
   918
      /* read ROWS section */
alpar@1
   919
      if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0))
alpar@1
   920
         error(csa, "missing ROWS indicator record\n");
alpar@1
   921
      read_rows(csa);
alpar@1
   922
      /* determine objective row */
alpar@1
   923
      if (parm->obj_name == NULL || parm->obj_name[0] == '\0')
alpar@1
   924
      {  /* use the first row of N type */
alpar@1
   925
         int i;
alpar@1
   926
         for (i = 1; i <= P->m; i++)
alpar@1
   927
         {  if (P->row[i]->type == GLP_FR)
alpar@1
   928
            {  csa->obj_row = i;
alpar@1
   929
               break;
alpar@1
   930
            }
alpar@1
   931
         }
alpar@1
   932
         if (csa->obj_row == 0)
alpar@1
   933
            warning(csa, "unable to determine objective row\n");
alpar@1
   934
      }
alpar@1
   935
      else
alpar@1
   936
      {  /* use a row with specified name */
alpar@1
   937
         int i;
alpar@1
   938
         for (i = 1; i <= P->m; i++)
alpar@1
   939
         {  xassert(P->row[i]->name != NULL);
alpar@1
   940
            if (strcmp(parm->obj_name, P->row[i]->name) == 0)
alpar@1
   941
            {  csa->obj_row = i;
alpar@1
   942
               break;
alpar@1
   943
            }
alpar@1
   944
         }
alpar@1
   945
         if (csa->obj_row == 0)
alpar@1
   946
            error(csa, "objective row `%s' not found\n",
alpar@1
   947
               parm->obj_name);
alpar@1
   948
      }
alpar@1
   949
      if (csa->obj_row != 0)
alpar@1
   950
      {  glp_set_obj_name(P, P->row[csa->obj_row]->name);
alpar@1
   951
         xprintf("Objective: %s\n", P->obj);
alpar@1
   952
      }
alpar@1
   953
      /* read COLUMNS section */
alpar@1
   954
      if (strcmp(csa->field, "COLUMNS") != 0)
alpar@1
   955
         error(csa, "missing COLUMNS indicator record\n");
alpar@1
   956
      read_columns(csa);
alpar@1
   957
      /* set objective coefficients */
alpar@1
   958
      if (csa->obj_row != 0)
alpar@1
   959
      {  GLPAIJ *aij;
alpar@1
   960
         for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij =
alpar@1
   961
            aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val);
alpar@1
   962
      }
alpar@1
   963
      /* read optional RHS section */
alpar@1
   964
      if (strcmp(csa->field, "RHS") == 0)
alpar@1
   965
         read_rhs(csa);
alpar@1
   966
      /* read optional RANGES section */
alpar@1
   967
      if (strcmp(csa->field, "RANGES") == 0)
alpar@1
   968
         read_ranges(csa);
alpar@1
   969
      /* read optional BOUNDS section */
alpar@1
   970
      if (strcmp(csa->field, "BOUNDS") == 0)
alpar@1
   971
         read_bounds(csa);
alpar@1
   972
      /* read ENDATA indicator record */
alpar@1
   973
      if (strcmp(csa->field, "ENDATA") != 0)
alpar@1
   974
         error(csa, "invalid use of %s indicator record\n",
alpar@1
   975
            csa->field);
alpar@1
   976
      /* print some statistics */
alpar@1
   977
      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
alpar@1
   978
         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
alpar@1
   979
         P->nnz, P->nnz == 1 ? "" : "s");
alpar@1
   980
      if (glp_get_num_int(P) > 0)
alpar@1
   981
      {  int ni = glp_get_num_int(P);
alpar@1
   982
         int nb = glp_get_num_bin(P);
alpar@1
   983
         if (ni == 1)
alpar@1
   984
         {  if (nb == 0)
alpar@1
   985
               xprintf("One variable is integer\n");
alpar@1
   986
            else
alpar@1
   987
               xprintf("One variable is binary\n");
alpar@1
   988
         }
alpar@1
   989
         else
alpar@1
   990
         {  xprintf("%d integer variables, ", ni);
alpar@1
   991
            if (nb == 0)
alpar@1
   992
               xprintf("none");
alpar@1
   993
            else if (nb == 1)
alpar@1
   994
               xprintf("one");
alpar@1
   995
            else if (nb == ni)
alpar@1
   996
               xprintf("all");
alpar@1
   997
            else
alpar@1
   998
               xprintf("%d", nb);
alpar@1
   999
            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
alpar@1
  1000
         }
alpar@1
  1001
      }
alpar@1
  1002
      xprintf("%d records were read\n", csa->recno);
alpar@1
  1003
      /* problem data has been successfully read */
alpar@1
  1004
      glp_delete_index(P);
alpar@1
  1005
      glp_sort_matrix(P);
alpar@1
  1006
      ret = 0;
alpar@1
  1007
done: if (csa->fp != NULL) xfclose(csa->fp);
alpar@1
  1008
      if (csa->work1 != NULL) xfree(csa->work1);
alpar@1
  1009
      if (csa->work2 != NULL) xfree(csa->work2);
alpar@1
  1010
      if (csa->work3 != NULL) xfree(csa->work3);
alpar@1
  1011
      if (ret != 0) glp_erase_prob(P);
alpar@1
  1012
      return ret;
alpar@1
  1013
}
alpar@1
  1014
alpar@1
  1015
/***********************************************************************
alpar@1
  1016
*  NAME
alpar@1
  1017
*
alpar@1
  1018
*  glp_write_mps - write problem data in MPS format
alpar@1
  1019
*
alpar@1
  1020
*  SYNOPSIS
alpar@1
  1021
*
alpar@1
  1022
*  int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
alpar@1
  1023
*     const char *fname);
alpar@1
  1024
*
alpar@1
  1025
*  DESCRIPTION
alpar@1
  1026
*
alpar@1
  1027
*  The routine glp_write_mps writes problem data in MPS format to a
alpar@1
  1028
*  text file.
alpar@1
  1029
*
alpar@1
  1030
*  The parameter fmt specifies the version of MPS format:
alpar@1
  1031
*
alpar@1
  1032
*  GLP_MPS_DECK - fixed (ancient) MPS format;
alpar@1
  1033
*  GLP_MPS_FILE - free (modern) MPS format.
alpar@1
  1034
*
alpar@1
  1035
*  The parameter parm is a pointer to the structure glp_mpscp, which
alpar@1
  1036
*  specifies control parameters used by the routine. If parm is NULL,
alpar@1
  1037
*  the routine uses default settings.
alpar@1
  1038
*
alpar@1
  1039
*  The character string fname specifies a name of the text file to be
alpar@1
  1040
*  written.
alpar@1
  1041
*
alpar@1
  1042
*  RETURNS
alpar@1
  1043
*
alpar@1
  1044
*  If the operation was successful, the routine glp_read_mps returns
alpar@1
  1045
*  zero. Otherwise, it prints an error message and returns non-zero. */
alpar@1
  1046
alpar@1
  1047
#define csa csa1
alpar@1
  1048
alpar@1
  1049
struct csa
alpar@1
  1050
{     /* common storage area */
alpar@1
  1051
      glp_prob *P;
alpar@1
  1052
      /* pointer to problem object */
alpar@1
  1053
      int deck;
alpar@1
  1054
      /* MPS format (0 - free, 1 - fixed) */
alpar@1
  1055
      const glp_mpscp *parm;
alpar@1
  1056
      /* pointer to control parameters */
alpar@1
  1057
      char field[255+1];
alpar@1
  1058
      /* field buffer */
alpar@1
  1059
};
alpar@1
  1060
alpar@1
  1061
static char *mps_name(struct csa *csa)
alpar@1
  1062
{     /* make problem name */
alpar@1
  1063
      char *f;
alpar@1
  1064
      if (csa->P->name == NULL)
alpar@1
  1065
         csa->field[0] = '\0';
alpar@1
  1066
      else if (csa->deck)
alpar@1
  1067
      {  strncpy(csa->field, csa->P->name, 8);
alpar@1
  1068
         csa->field[8] = '\0';
alpar@1
  1069
      }
alpar@1
  1070
      else
alpar@1
  1071
         strcpy(csa->field, csa->P->name);
alpar@1
  1072
      for (f = csa->field; *f != '\0'; f++)
alpar@1
  1073
         if (*f == ' ') *f = '_';
alpar@1
  1074
      return csa->field;
alpar@1
  1075
}
alpar@1
  1076
alpar@1
  1077
static char *row_name(struct csa *csa, int i)
alpar@1
  1078
{     /* make i-th row name */
alpar@1
  1079
      char *f;
alpar@1
  1080
      xassert(0 <= i && i <= csa->P->m);
alpar@1
  1081
      if (i == 0 || csa->P->row[i]->name == NULL ||
alpar@1
  1082
          csa->deck && strlen(csa->P->row[i]->name) > 8)
alpar@1
  1083
         sprintf(csa->field, "R%07d", i);
alpar@1
  1084
      else
alpar@1
  1085
      {  strcpy(csa->field, csa->P->row[i]->name);
alpar@1
  1086
         for (f = csa->field; *f != '\0'; f++)
alpar@1
  1087
            if (*f == ' ') *f = '_';
alpar@1
  1088
      }
alpar@1
  1089
      return csa->field;
alpar@1
  1090
}
alpar@1
  1091
alpar@1
  1092
static char *col_name(struct csa *csa, int j)
alpar@1
  1093
{     /* make j-th column name */
alpar@1
  1094
      char *f;
alpar@1
  1095
      xassert(1 <= j && j <= csa->P->n);
alpar@1
  1096
      if (csa->P->col[j]->name == NULL ||
alpar@1
  1097
          csa->deck && strlen(csa->P->col[j]->name) > 8)
alpar@1
  1098
         sprintf(csa->field, "C%07d", j);
alpar@1
  1099
      else
alpar@1
  1100
      {  strcpy(csa->field, csa->P->col[j]->name);
alpar@1
  1101
         for (f = csa->field; *f != '\0'; f++)
alpar@1
  1102
            if (*f == ' ') *f = '_';
alpar@1
  1103
      }
alpar@1
  1104
      return csa->field;
alpar@1
  1105
}
alpar@1
  1106
alpar@1
  1107
static char *mps_numb(struct csa *csa, double val)
alpar@1
  1108
{     /* format floating-point number */
alpar@1
  1109
      int dig;
alpar@1
  1110
      char *exp;
alpar@1
  1111
      for (dig = 12; dig >= 6; dig--)
alpar@1
  1112
      {  if (val != 0.0 && fabs(val) < 0.002)
alpar@1
  1113
            sprintf(csa->field, "%.*E", dig-1, val);
alpar@1
  1114
         else
alpar@1
  1115
            sprintf(csa->field, "%.*G", dig, val);
alpar@1
  1116
         exp = strchr(csa->field, 'E');
alpar@1
  1117
         if (exp != NULL)
alpar@1
  1118
            sprintf(exp+1, "%d", atoi(exp+1));
alpar@1
  1119
         if (strlen(csa->field) <= 12) break;
alpar@1
  1120
      }
alpar@1
  1121
      xassert(strlen(csa->field) <= 12);
alpar@1
  1122
      return csa->field;
alpar@1
  1123
}
alpar@1
  1124
alpar@1
  1125
int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
alpar@1
  1126
      const char *fname)
alpar@1
  1127
{     /* write problem data in MPS format */
alpar@1
  1128
      glp_mpscp _parm;
alpar@1
  1129
      struct csa _csa, *csa = &_csa;
alpar@1
  1130
      XFILE *fp;
alpar@1
  1131
      int out_obj, one_col = 0, empty = 0;
alpar@1
  1132
      int i, j, recno, marker, count, gap, ret;
alpar@1
  1133
      xprintf("Writing problem data to `%s'...\n", fname);
alpar@1
  1134
      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
alpar@1
  1135
         xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt);
alpar@1
  1136
      if (parm == NULL)
alpar@1
  1137
         glp_init_mpscp(&_parm), parm = &_parm;
alpar@1
  1138
      /* check control parameters */
alpar@1
  1139
      check_parm("glp_write_mps", parm);
alpar@1
  1140
      /* initialize common storage area */
alpar@1
  1141
      csa->P = P;
alpar@1
  1142
      csa->deck = (fmt == GLP_MPS_DECK);
alpar@1
  1143
      csa->parm = parm;
alpar@1
  1144
      /* create output MPS file */
alpar@1
  1145
      fp = xfopen(fname, "w"), recno = 0;
alpar@1
  1146
      if (fp == NULL)
alpar@1
  1147
      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
alpar@1
  1148
         ret = 1;
alpar@1
  1149
         goto done;
alpar@1
  1150
      }
alpar@1
  1151
      /* write comment records */
alpar@1
  1152
      xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:",
alpar@1
  1153
         P->name == NULL ? "" : P->name), recno++;
alpar@1
  1154
      xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ?
alpar@1
  1155
         "LP" : "MIP"), recno++;
alpar@1
  1156
      xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++;
alpar@1
  1157
      if (glp_get_num_int(P) == 0)
alpar@1
  1158
         xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++;
alpar@1
  1159
      else
alpar@1
  1160
         xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n",
alpar@1
  1161
            "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)),
alpar@1
  1162
            recno++;
alpar@1
  1163
      xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++;
alpar@1
  1164
      xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" :
alpar@1
  1165
         "Free MPS"), recno++;
alpar@1
  1166
      xfprintf(fp, "*\n", recno++);
alpar@1
  1167
      /* write NAME indicator record */
alpar@1
  1168
      xfprintf(fp, "NAME%*s%s\n",
alpar@1
  1169
         P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)),
alpar@1
  1170
         recno++;
alpar@1
  1171
#if 1
alpar@1
  1172
      /* determine whether to write the objective row */
alpar@1
  1173
      out_obj = 1;
alpar@1
  1174
      for (i = 1; i <= P->m; i++)
alpar@1
  1175
      {  if (P->row[i]->type == GLP_FR)
alpar@1
  1176
         {  out_obj = 0;
alpar@1
  1177
            break;
alpar@1
  1178
         }
alpar@1
  1179
      }
alpar@1
  1180
#endif
alpar@1
  1181
      /* write ROWS section */
alpar@1
  1182
      xfprintf(fp, "ROWS\n"), recno++;
alpar@1
  1183
      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
alpar@1
  1184
      {  int type;
alpar@1
  1185
         type = (i == 0 ? GLP_FR : P->row[i]->type);
alpar@1
  1186
         if (type == GLP_FR)
alpar@1
  1187
            type = 'N';
alpar@1
  1188
         else if (type == GLP_LO)
alpar@1
  1189
            type = 'G';
alpar@1
  1190
         else if (type == GLP_UP)
alpar@1
  1191
            type = 'L';
alpar@1
  1192
         else if (type == GLP_DB || type == GLP_FX)
alpar@1
  1193
            type = 'E';
alpar@1
  1194
         else
alpar@1
  1195
            xassert(type != type);
alpar@1
  1196
         xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "",
alpar@1
  1197
            row_name(csa, i)), recno++;
alpar@1
  1198
      }
alpar@1
  1199
      /* write COLUMNS section */
alpar@1
  1200
      xfprintf(fp, "COLUMNS\n"), recno++;
alpar@1
  1201
      marker = 0;
alpar@1
  1202
      for (j = 1; j <= P->n; j++)
alpar@1
  1203
      {  GLPAIJ cj, *aij;
alpar@1
  1204
         int kind;
alpar@1
  1205
         kind = P->col[j]->kind;
alpar@1
  1206
         if (kind == GLP_CV)
alpar@1
  1207
         {  if (marker % 2 == 1)
alpar@1
  1208
            {  /* close current integer block */
alpar@1
  1209
               marker++;
alpar@1
  1210
               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
alpar@1
  1211
                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
alpar@1
  1212
                  csa->deck ? 17 : 1, ""), recno++;
alpar@1
  1213
            }
alpar@1
  1214
         }
alpar@1
  1215
         else if (kind == GLP_IV)
alpar@1
  1216
         {  if (marker % 2 == 0)
alpar@1
  1217
            {  /* open new integer block */
alpar@1
  1218
               marker++;
alpar@1
  1219
               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n",
alpar@1
  1220
                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
alpar@1
  1221
                  csa->deck ? 17 : 1, ""), recno++;
alpar@1
  1222
            }
alpar@1
  1223
         }
alpar@1
  1224
         else
alpar@1
  1225
            xassert(kind != kind);
alpar@1
  1226
         if (out_obj && P->col[j]->coef != 0.0)
alpar@1
  1227
         {  /* make fake objective coefficient */
alpar@1
  1228
            aij = &cj;
alpar@1
  1229
            aij->row = NULL;
alpar@1
  1230
            aij->val = P->col[j]->coef;
alpar@1
  1231
            aij->c_next = P->col[j]->ptr;
alpar@1
  1232
         }
alpar@1
  1233
         else
alpar@1
  1234
            aij = P->col[j]->ptr;
alpar@1
  1235
#if 1 /* FIXME */
alpar@1
  1236
         if (aij == NULL)
alpar@1
  1237
         {  /* empty column */
alpar@1
  1238
            empty++;
alpar@1
  1239
            xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
alpar@1
  1240
               csa->deck ? 8 : 1, col_name(csa, j));
alpar@1
  1241
            /* we need a row */
alpar@1
  1242
            xassert(P->m > 0);
alpar@1
  1243
            xfprintf(fp, "%*s%-*s",
alpar@1
  1244
               csa->deck ? 2 : 1, "", csa->deck ? 8 : 1,
alpar@1
  1245
               row_name(csa, 1));
alpar@1
  1246
            xfprintf(fp, "%*s0%*s$ empty column\n",
alpar@1
  1247
               csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++;
alpar@1
  1248
         }
alpar@1
  1249
#endif
alpar@1
  1250
         count = 0;
alpar@1
  1251
         for (aij = aij; aij != NULL; aij = aij->c_next)
alpar@1
  1252
         {  if (one_col || count % 2 == 0)
alpar@1
  1253
               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
alpar@1
  1254
                  csa->deck ? 8 : 1, col_name(csa, j));
alpar@1
  1255
            gap = (one_col || count % 2 == 0 ? 2 : 3);
alpar@1
  1256
            xfprintf(fp, "%*s%-*s",
alpar@1
  1257
               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
alpar@1
  1258
               row_name(csa, aij->row == NULL ? 0 : aij->row->i));
alpar@1
  1259
            xfprintf(fp, "%*s%*s",
alpar@1
  1260
               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
alpar@1
  1261
               mps_numb(csa, aij->val)), count++;
alpar@1
  1262
            if (one_col || count % 2 == 0)
alpar@1
  1263
               xfprintf(fp, "\n"), recno++;
alpar@1
  1264
         }
alpar@1
  1265
         if (!(one_col || count % 2 == 0))
alpar@1
  1266
            xfprintf(fp, "\n"), recno++;
alpar@1
  1267
      }
alpar@1
  1268
      if (marker % 2 == 1)
alpar@1
  1269
      {  /* close last integer block */
alpar@1
  1270
         marker++;
alpar@1
  1271
         xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
alpar@1
  1272
            csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
alpar@1
  1273
            csa->deck ? 17 : 1, ""), recno++;
alpar@1
  1274
      }
alpar@1
  1275
#if 1
alpar@1
  1276
      if (empty > 0)
alpar@1
  1277
         xprintf("Warning: problem has %d empty column(s)\n", empty);
alpar@1
  1278
#endif
alpar@1
  1279
      /* write RHS section */
alpar@1
  1280
      xfprintf(fp, "RHS\n"), recno++;
alpar@1
  1281
      count = 0;
alpar@1
  1282
      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
alpar@1
  1283
      {  int type;
alpar@1
  1284
         double rhs;
alpar@1
  1285
         if (i == 0)
alpar@1
  1286
            rhs = P->c0;
alpar@1
  1287
         else
alpar@1
  1288
         {  type = P->row[i]->type;
alpar@1
  1289
            if (type == GLP_FR)
alpar@1
  1290
               rhs = 0.0;
alpar@1
  1291
            else if (type == GLP_LO)
alpar@1
  1292
               rhs = P->row[i]->lb;
alpar@1
  1293
            else if (type == GLP_UP)
alpar@1
  1294
               rhs = P->row[i]->ub;
alpar@1
  1295
            else if (type == GLP_DB || type == GLP_FX)
alpar@1
  1296
               rhs = P->row[i]->lb;
alpar@1
  1297
            else
alpar@1
  1298
               xassert(type != type);
alpar@1
  1299
         }
alpar@1
  1300
         if (rhs != 0.0)
alpar@1
  1301
         {  if (one_col || count % 2 == 0)
alpar@1
  1302
               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
alpar@1
  1303
                  csa->deck ? 8 : 1, "RHS1");
alpar@1
  1304
            gap = (one_col || count % 2 == 0 ? 2 : 3);
alpar@1
  1305
            xfprintf(fp, "%*s%-*s",
alpar@1
  1306
               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
alpar@1
  1307
               row_name(csa, i));
alpar@1
  1308
            xfprintf(fp, "%*s%*s",
alpar@1
  1309
               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
alpar@1
  1310
               mps_numb(csa, rhs)), count++;
alpar@1
  1311
            if (one_col || count % 2 == 0)
alpar@1
  1312
               xfprintf(fp, "\n"), recno++;
alpar@1
  1313
         }
alpar@1
  1314
      }
alpar@1
  1315
      if (!(one_col || count % 2 == 0))
alpar@1
  1316
         xfprintf(fp, "\n"), recno++;
alpar@1
  1317
      /* write RANGES section */
alpar@1
  1318
      for (i = P->m; i >= 1; i--)
alpar@1
  1319
         if (P->row[i]->type == GLP_DB) break;
alpar@1
  1320
      if (i == 0) goto bnds;
alpar@1
  1321
      xfprintf(fp, "RANGES\n"), recno++;
alpar@1
  1322
      count = 0;
alpar@1
  1323
      for (i = 1; i <= P->m; i++)
alpar@1
  1324
      {  if (P->row[i]->type == GLP_DB)
alpar@1
  1325
         {  if (one_col || count % 2 == 0)
alpar@1
  1326
               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
alpar@1
  1327
                  csa->deck ? 8 : 1, "RNG1");
alpar@1
  1328
            gap = (one_col || count % 2 == 0 ? 2 : 3);
alpar@1
  1329
            xfprintf(fp, "%*s%-*s",
alpar@1
  1330
               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
alpar@1
  1331
               row_name(csa, i));
alpar@1
  1332
            xfprintf(fp, "%*s%*s",
alpar@1
  1333
               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
alpar@1
  1334
               mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++;
alpar@1
  1335
            if (one_col || count % 2 == 0)
alpar@1
  1336
               xfprintf(fp, "\n"), recno++;
alpar@1
  1337
         }
alpar@1
  1338
      }
alpar@1
  1339
      if (!(one_col || count % 2 == 0))
alpar@1
  1340
         xfprintf(fp, "\n"), recno++;
alpar@1
  1341
bnds: /* write BOUNDS section */
alpar@1
  1342
      for (j = P->n; j >= 1; j--)
alpar@1
  1343
         if (!(P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0))
alpar@1
  1344
            break;
alpar@1
  1345
      if (j == 0) goto endt;
alpar@1
  1346
      xfprintf(fp, "BOUNDS\n"), recno++;
alpar@1
  1347
      for (j = 1; j <= P->n; j++)
alpar@1
  1348
      {  int type, data[2];
alpar@1
  1349
         double bnd[2];
alpar@1
  1350
         char *spec[2];
alpar@1
  1351
         spec[0] = spec[1] = NULL;
alpar@1
  1352
         type = P->col[j]->type;
alpar@1
  1353
         if (type == GLP_FR)
alpar@1
  1354
            spec[0] = "FR", data[0] = 0;
alpar@1
  1355
         else if (type == GLP_LO)
alpar@1
  1356
         {  if (P->col[j]->lb != 0.0)
alpar@1
  1357
               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
alpar@1
  1358
            if (P->col[j]->kind == GLP_IV)
alpar@1
  1359
               spec[1] = "PL", data[1] = 0;
alpar@1
  1360
         }
alpar@1
  1361
         else if (type == GLP_UP)
alpar@1
  1362
         {  spec[0] = "MI", data[0] = 0;
alpar@1
  1363
            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
alpar@1
  1364
         }
alpar@1
  1365
         else if (type == GLP_DB)
alpar@1
  1366
         {  if (P->col[j]->lb != 0.0)
alpar@1
  1367
               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
alpar@1
  1368
            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
alpar@1
  1369
         }
alpar@1
  1370
         else if (type == GLP_FX)
alpar@1
  1371
            spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb;
alpar@1
  1372
         else
alpar@1
  1373
            xassert(type != type);
alpar@1
  1374
         for (i = 0; i <= 1; i++)
alpar@1
  1375
         {  if (spec[i] != NULL)
alpar@1
  1376
            {  xfprintf(fp, " %s %-*s%*s%-*s", spec[i],
alpar@1
  1377
                  csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "",
alpar@1
  1378
                  csa->deck ? 8 : 1, col_name(csa, j));
alpar@1
  1379
               if (data[i])
alpar@1
  1380
                  xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "",
alpar@1
  1381
                     csa->deck ? 12 : 1, mps_numb(csa, bnd[i]));
alpar@1
  1382
               xfprintf(fp, "\n"), recno++;
alpar@1
  1383
            }
alpar@1
  1384
         }
alpar@1
  1385
      }
alpar@1
  1386
endt: /* write ENDATA indicator record */
alpar@1
  1387
      xfprintf(fp, "ENDATA\n"), recno++;
alpar@1
  1388
      xfflush(fp);
alpar@1
  1389
      if (xferror(fp))
alpar@1
  1390
      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
alpar@1
  1391
         ret = 1;
alpar@1
  1392
         goto done;
alpar@1
  1393
      }
alpar@1
  1394
      /* problem data has been successfully written */
alpar@1
  1395
      xprintf("%d records were written\n", recno);
alpar@1
  1396
      ret = 0;
alpar@1
  1397
done: if (fp != NULL) xfclose(fp);
alpar@1
  1398
      return ret;
alpar@1
  1399
}
alpar@1
  1400
alpar@1
  1401
/* eof */