src/glpdmx.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     1 /* glpdmx.c (reading/writing data in DIMACS format) */
     2 
     3 /***********************************************************************
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
     5 *
     6 *  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
     7 *  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
     8 *  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
     9 *  E-mail: <mao@gnu.org>.
    10 *
    11 *  GLPK is free software: you can redistribute it and/or modify it
    12 *  under the terms of the GNU General Public License as published by
    13 *  the Free Software Foundation, either version 3 of the License, or
    14 *  (at your option) any later version.
    15 *
    16 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
    17 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    18 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    19 *  License for more details.
    20 *
    21 *  You should have received a copy of the GNU General Public License
    22 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
    23 ***********************************************************************/
    24 
    25 #define _GLPSTD_STDIO
    26 #include "glpapi.h"
    27 
    28 struct csa
    29 {     /* common storage area */
    30       jmp_buf jump;
    31       /* label for go to in case of error */
    32       const char *fname;
    33       /* name of input text file */
    34       XFILE *fp;
    35       /* stream assigned to input text file */
    36       int count;
    37       /* line count */
    38       int c;
    39       /* current character */
    40       char field[255+1];
    41       /* data field */
    42       int empty;
    43       /* warning 'empty line ignored' was printed */
    44       int nonint;
    45       /* warning 'non-integer data detected' was printed */
    46 };
    47 
    48 static void error(struct csa *csa, const char *fmt, ...)
    49 {     /* print error message and terminate processing */
    50       va_list arg;
    51       xprintf("%s:%d: error: ", csa->fname, csa->count);
    52       va_start(arg, fmt);
    53       xvprintf(fmt, arg);
    54       va_end(arg);
    55       xprintf("\n");
    56       longjmp(csa->jump, 1);
    57       /* no return */
    58 }
    59 
    60 static void warning(struct csa *csa, const char *fmt, ...)
    61 {     /* print warning message and continue processing */
    62       va_list arg;
    63       xprintf("%s:%d: warning: ", csa->fname, csa->count);
    64       va_start(arg, fmt);
    65       xvprintf(fmt, arg);
    66       va_end(arg);
    67       xprintf("\n");
    68       return;
    69 }
    70 
    71 static void read_char(struct csa *csa)
    72 {     /* read character from input text file */
    73       int c;
    74       if (csa->c == '\n') csa->count++;
    75       c = xfgetc(csa->fp);
    76       if (c < 0)
    77       {  if (xferror(csa->fp))
    78             error(csa, "read error - %s", xerrmsg());
    79          else if (csa->c == '\n')
    80             error(csa, "unexpected end of file");
    81          else
    82          {  warning(csa, "missing final end of line");
    83             c = '\n';
    84          }
    85       }
    86       else if (c == '\n')
    87          ;
    88       else if (isspace(c))
    89          c = ' ';
    90       else if (iscntrl(c))
    91          error(csa, "invalid control character 0x%02X", c);
    92       csa->c = c;
    93       return;
    94 }
    95 
    96 static void read_designator(struct csa *csa)
    97 {     /* read one-character line designator */
    98       xassert(csa->c == '\n');
    99       read_char(csa);
   100       for (;;)
   101       {  /* skip preceding white-space characters */
   102          while (csa->c == ' ')
   103             read_char(csa);
   104          if (csa->c == '\n')
   105          {  /* ignore empty line */
   106             if (!csa->empty)
   107             {  warning(csa, "empty line ignored");
   108                csa->empty = 1;
   109             }
   110             read_char(csa);
   111          }
   112          else if (csa->c == 'c')
   113          {  /* skip comment line */
   114             while (csa->c != '\n')
   115                read_char(csa);
   116             read_char(csa);
   117          }
   118          else
   119          {  /* hmm... looks like a line designator */
   120             csa->field[0] = (char)csa->c, csa->field[1] = '\0';
   121             /* check that it is followed by a white-space character */
   122             read_char(csa);
   123             if (!(csa->c == ' ' || csa->c == '\n'))
   124                error(csa, "line designator missing or invalid");
   125             break;
   126          }
   127       }
   128       return;
   129 }
   130 
   131 static void read_field(struct csa *csa)
   132 {     /* read data field */
   133       int len = 0;
   134       /* skip preceding white-space characters */
   135       while (csa->c == ' ')
   136          read_char(csa);
   137       /* scan data field */
   138       if (csa->c == '\n')
   139          error(csa, "unexpected end of line");
   140       while (!(csa->c == ' ' || csa->c == '\n'))
   141       {  if (len == sizeof(csa->field)-1)
   142             error(csa, "data field `%.15s...' too long", csa->field);
   143          csa->field[len++] = (char)csa->c;
   144          read_char(csa);
   145       }
   146       csa->field[len] = '\0';
   147       return;
   148 }
   149 
   150 static void end_of_line(struct csa *csa)
   151 {     /* skip white-space characters until end of line */
   152       while (csa->c == ' ')
   153          read_char(csa);
   154       if (csa->c != '\n')
   155          error(csa, "too many data fields specified");
   156       return;
   157 }
   158 
   159 static void check_int(struct csa *csa, double num)
   160 {     /* print a warning if non-integer data are detected */
   161       if (!csa->nonint && num != floor(num))
   162       {  warning(csa, "non-integer data detected");
   163          csa->nonint = 1;
   164       }
   165       return;
   166 }
   167 
   168 /***********************************************************************
   169 *  NAME
   170 *
   171 *  glp_read_mincost - read min-cost flow problem data in DIMACS format
   172 *
   173 *  SYNOPSIS
   174 *
   175 *  int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   176 *     int a_cost, const char *fname);
   177 *
   178 *  DESCRIPTION
   179 *
   180 *  The routine glp_read_mincost reads minimum cost flow problem data in
   181 *  DIMACS format from a text file.
   182 *
   183 *  RETURNS
   184 *
   185 *  If the operation was successful, the routine returns zero. Otherwise
   186 *  it prints an error message and returns non-zero. */
   187 
   188 int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   189       int a_cost, const char *fname)
   190 {     struct csa _csa, *csa = &_csa;
   191       glp_vertex *v;
   192       glp_arc *a;
   193       int i, j, k, nv, na, ret = 0;
   194       double rhs, low, cap, cost;
   195       char *flag = NULL;
   196       if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
   197          xerror("glp_read_mincost: v_rhs = %d; invalid offset\n",
   198             v_rhs);
   199       if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
   200          xerror("glp_read_mincost: a_low = %d; invalid offset\n",
   201             a_low);
   202       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   203          xerror("glp_read_mincost: a_cap = %d; invalid offset\n",
   204             a_cap);
   205       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   206          xerror("glp_read_mincost: a_cost = %d; invalid offset\n",
   207             a_cost);
   208       glp_erase_graph(G, G->v_size, G->a_size);
   209       if (setjmp(csa->jump))
   210       {  ret = 1;
   211          goto done;
   212       }
   213       csa->fname = fname;
   214       csa->fp = NULL;
   215       csa->count = 0;
   216       csa->c = '\n';
   217       csa->field[0] = '\0';
   218       csa->empty = csa->nonint = 0;
   219       xprintf("Reading min-cost flow problem data from `%s'...\n",
   220          fname);
   221       csa->fp = xfopen(fname, "r");
   222       if (csa->fp == NULL)
   223       {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   224          longjmp(csa->jump, 1);
   225       }
   226       /* read problem line */
   227       read_designator(csa);
   228       if (strcmp(csa->field, "p") != 0)
   229          error(csa, "problem line missing or invalid");
   230       read_field(csa);
   231       if (strcmp(csa->field, "min") != 0)
   232          error(csa, "wrong problem designator; `min' expected");
   233       read_field(csa);
   234       if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
   235          error(csa, "number of nodes missing or invalid");
   236       read_field(csa);
   237       if (!(str2int(csa->field, &na) == 0 && na >= 0))
   238          error(csa, "number of arcs missing or invalid");
   239       xprintf("Flow network has %d node%s and %d arc%s\n",
   240          nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
   241       if (nv > 0) glp_add_vertices(G, nv);
   242       end_of_line(csa);
   243       /* read node descriptor lines */
   244       flag = xcalloc(1+nv, sizeof(char));
   245       memset(&flag[1], 0, nv * sizeof(char));
   246       if (v_rhs >= 0)
   247       {  rhs = 0.0;
   248          for (i = 1; i <= nv; i++)
   249          {  v = G->v[i];
   250             memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
   251          }
   252       }
   253       for (;;)
   254       {  read_designator(csa);
   255          if (strcmp(csa->field, "n") != 0) break;
   256          read_field(csa);
   257          if (str2int(csa->field, &i) != 0)
   258             error(csa, "node number missing or invalid");
   259          if (!(1 <= i && i <= nv))
   260             error(csa, "node number %d out of range", i);
   261          if (flag[i])
   262             error(csa, "duplicate descriptor of node %d", i);
   263          read_field(csa);
   264          if (str2num(csa->field, &rhs) != 0)
   265             error(csa, "node supply/demand missing or invalid");
   266          check_int(csa, rhs);
   267          if (v_rhs >= 0)
   268          {  v = G->v[i];
   269             memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
   270          }
   271          flag[i] = 1;
   272          end_of_line(csa);
   273       }
   274       xfree(flag), flag = NULL;
   275       /* read arc descriptor lines */
   276       for (k = 1; k <= na; k++)
   277       {  if (k > 1) read_designator(csa);
   278          if (strcmp(csa->field, "a") != 0)
   279             error(csa, "wrong line designator; `a' expected");
   280          read_field(csa);
   281          if (str2int(csa->field, &i) != 0)
   282             error(csa, "starting node number missing or invalid");
   283          if (!(1 <= i && i <= nv))
   284             error(csa, "starting node number %d out of range", i);
   285          read_field(csa);
   286          if (str2int(csa->field, &j) != 0)
   287             error(csa, "ending node number missing or invalid");
   288          if (!(1 <= j && j <= nv))
   289             error(csa, "ending node number %d out of range", j);
   290          read_field(csa);
   291          if (!(str2num(csa->field, &low) == 0 && low >= 0.0))
   292             error(csa, "lower bound of arc flow missing or invalid");
   293          check_int(csa, low);
   294          read_field(csa);
   295          if (!(str2num(csa->field, &cap) == 0 && cap >= low))
   296             error(csa, "upper bound of arc flow missing or invalid");
   297          check_int(csa, cap);
   298          read_field(csa);
   299          if (str2num(csa->field, &cost) != 0)
   300             error(csa, "per-unit cost of arc flow missing or invalid");
   301          check_int(csa, cost);
   302          a = glp_add_arc(G, i, j);
   303          if (a_low >= 0)
   304             memcpy((char *)a->data + a_low, &low, sizeof(double));
   305          if (a_cap >= 0)
   306             memcpy((char *)a->data + a_cap, &cap, sizeof(double));
   307          if (a_cost >= 0)
   308             memcpy((char *)a->data + a_cost, &cost, sizeof(double));
   309          end_of_line(csa);
   310       }
   311       xprintf("%d lines were read\n", csa->count);
   312 done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   313       if (csa->fp != NULL) xfclose(csa->fp);
   314       if (flag != NULL) xfree(flag);
   315       return ret;
   316 }
   317 
   318 /***********************************************************************
   319 *  NAME
   320 *
   321 *  glp_write_mincost - write min-cost flow problem data in DIMACS format
   322 *
   323 *  SYNOPSIS
   324 *
   325 *  int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   326 *     int a_cost, const char *fname);
   327 *
   328 *  DESCRIPTION
   329 *
   330 *  The routine glp_write_mincost writes minimum cost flow problem data
   331 *  in DIMACS format to a text file.
   332 *
   333 *  RETURNS
   334 *
   335 *  If the operation was successful, the routine returns zero. Otherwise
   336 *  it prints an error message and returns non-zero. */
   337 
   338 int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   339       int a_cost, const char *fname)
   340 {     XFILE *fp;
   341       glp_vertex *v;
   342       glp_arc *a;
   343       int i, count = 0, ret;
   344       double rhs, low, cap, cost;
   345       if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
   346          xerror("glp_write_mincost: v_rhs = %d; invalid offset\n",
   347             v_rhs);
   348       if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
   349          xerror("glp_write_mincost: a_low = %d; invalid offset\n",
   350             a_low);
   351       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   352          xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
   353             a_cap);
   354       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   355          xerror("glp_write_mincost: a_cost = %d; invalid offset\n",
   356             a_cost);
   357       xprintf("Writing min-cost flow problem data to `%s'...\n",
   358          fname);
   359       fp = xfopen(fname, "w");
   360       if (fp == NULL)
   361       {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   362          ret = 1;
   363          goto done;
   364       }
   365       xfprintf(fp, "c %s\n",
   366          G->name == NULL ? "unknown" : G->name), count++;
   367       xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++;
   368       if (v_rhs >= 0)
   369       {  for (i = 1; i <= G->nv; i++)
   370          {  v = G->v[i];
   371             memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
   372             if (rhs != 0.0)
   373                xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++;
   374          }
   375       }
   376       for (i = 1; i <= G->nv; i++)
   377       {  v = G->v[i];
   378          for (a = v->out; a != NULL; a = a->t_next)
   379          {  if (a_low >= 0)
   380                memcpy(&low, (char *)a->data + a_low, sizeof(double));
   381             else
   382                low = 0.0;
   383             if (a_cap >= 0)
   384                memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
   385             else
   386                cap = 1.0;
   387             if (a_cost >= 0)
   388                memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
   389             else
   390                cost = 0.0;
   391             xfprintf(fp, "a %d %d %.*g %.*g %.*g\n",
   392                a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap,
   393                DBL_DIG, cost), count++;
   394          }
   395       }
   396       xfprintf(fp, "c eof\n"), count++;
   397       xfflush(fp);
   398       if (xferror(fp))
   399       {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   400          ret = 1;
   401          goto done;
   402       }
   403       xprintf("%d lines were written\n", count);
   404       ret = 0;
   405 done: if (fp != NULL) xfclose(fp);
   406       return ret;
   407 }
   408 
   409 /***********************************************************************
   410 *  NAME
   411 *
   412 *  glp_read_maxflow - read maximum flow problem data in DIMACS format
   413 *
   414 *  SYNOPSIS
   415 *
   416 *  int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
   417 *     const char *fname);
   418 *
   419 *  DESCRIPTION
   420 *
   421 *  The routine glp_read_maxflow reads maximum flow problem data in
   422 *  DIMACS format from a text file.
   423 *
   424 *  RETURNS
   425 *
   426 *  If the operation was successful, the routine returns zero. Otherwise
   427 *  it prints an error message and returns non-zero. */
   428 
   429 int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap,
   430       const char *fname)
   431 {     struct csa _csa, *csa = &_csa;
   432       glp_arc *a;
   433       int i, j, k, s, t, nv, na, ret = 0;
   434       double cap;
   435       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   436          xerror("glp_read_maxflow: a_cap = %d; invalid offset\n",
   437             a_cap);
   438       glp_erase_graph(G, G->v_size, G->a_size);
   439       if (setjmp(csa->jump))
   440       {  ret = 1;
   441          goto done;
   442       }
   443       csa->fname = fname;
   444       csa->fp = NULL;
   445       csa->count = 0;
   446       csa->c = '\n';
   447       csa->field[0] = '\0';
   448       csa->empty = csa->nonint = 0;
   449       xprintf("Reading maximum flow problem data from `%s'...\n",
   450          fname);
   451       csa->fp = xfopen(fname, "r");
   452       if (csa->fp == NULL)
   453       {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   454          longjmp(csa->jump, 1);
   455       }
   456       /* read problem line */
   457       read_designator(csa);
   458       if (strcmp(csa->field, "p") != 0)
   459          error(csa, "problem line missing or invalid");
   460       read_field(csa);
   461       if (strcmp(csa->field, "max") != 0)
   462          error(csa, "wrong problem designator; `max' expected");
   463       read_field(csa);
   464       if (!(str2int(csa->field, &nv) == 0 && nv >= 2))
   465          error(csa, "number of nodes missing or invalid");
   466       read_field(csa);
   467       if (!(str2int(csa->field, &na) == 0 && na >= 0))
   468          error(csa, "number of arcs missing or invalid");
   469       xprintf("Flow network has %d node%s and %d arc%s\n",
   470          nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
   471       if (nv > 0) glp_add_vertices(G, nv);
   472       end_of_line(csa);
   473       /* read node descriptor lines */
   474       s = t = 0;
   475       for (;;)
   476       {  read_designator(csa);
   477          if (strcmp(csa->field, "n") != 0) break;
   478          read_field(csa);
   479          if (str2int(csa->field, &i) != 0)
   480             error(csa, "node number missing or invalid");
   481          if (!(1 <= i && i <= nv))
   482             error(csa, "node number %d out of range", i);
   483          read_field(csa);
   484          if (strcmp(csa->field, "s") == 0)
   485          {  if (s > 0)
   486                error(csa, "only one source node allowed");
   487             s = i;
   488          }
   489          else if (strcmp(csa->field, "t") == 0)
   490          {  if (t > 0)
   491                error(csa, "only one sink node allowed");
   492             t = i;
   493          }
   494          else
   495             error(csa, "wrong node designator; `s' or `t' expected");
   496          if (s > 0 && s == t)
   497             error(csa, "source and sink nodes must be distinct");
   498          end_of_line(csa);
   499       }
   500       if (s == 0)
   501          error(csa, "source node descriptor missing\n");
   502       if (t == 0)
   503          error(csa, "sink node descriptor missing\n");
   504       if (_s != NULL) *_s = s;
   505       if (_t != NULL) *_t = t;
   506       /* read arc descriptor lines */
   507       for (k = 1; k <= na; k++)
   508       {  if (k > 1) read_designator(csa);
   509          if (strcmp(csa->field, "a") != 0)
   510             error(csa, "wrong line designator; `a' expected");
   511          read_field(csa);
   512          if (str2int(csa->field, &i) != 0)
   513             error(csa, "starting node number missing or invalid");
   514          if (!(1 <= i && i <= nv))
   515             error(csa, "starting node number %d out of range", i);
   516          read_field(csa);
   517          if (str2int(csa->field, &j) != 0)
   518             error(csa, "ending node number missing or invalid");
   519          if (!(1 <= j && j <= nv))
   520             error(csa, "ending node number %d out of range", j);
   521          read_field(csa);
   522          if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0))
   523             error(csa, "arc capacity missing or invalid");
   524          check_int(csa, cap);
   525          a = glp_add_arc(G, i, j);
   526          if (a_cap >= 0)
   527             memcpy((char *)a->data + a_cap, &cap, sizeof(double));
   528          end_of_line(csa);
   529       }
   530       xprintf("%d lines were read\n", csa->count);
   531 done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   532       if (csa->fp != NULL) xfclose(csa->fp);
   533       return ret;
   534 }
   535 
   536 /***********************************************************************
   537 *  NAME
   538 *
   539 *  glp_write_maxflow - write maximum flow problem data in DIMACS format
   540 *
   541 *  SYNOPSIS
   542 *
   543 *  int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
   544 *     const char *fname);
   545 *
   546 *  DESCRIPTION
   547 *
   548 *  The routine glp_write_maxflow writes maximum flow problem data in
   549 *  DIMACS format to a text file.
   550 *
   551 *  RETURNS
   552 *
   553 *  If the operation was successful, the routine returns zero. Otherwise
   554 *  it prints an error message and returns non-zero. */
   555 
   556 int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
   557       const char *fname)
   558 {     XFILE *fp;
   559       glp_vertex *v;
   560       glp_arc *a;
   561       int i, count = 0, ret;
   562       double cap;
   563       if (!(1 <= s && s <= G->nv))
   564          xerror("glp_write_maxflow: s = %d; source node number out of r"
   565             "ange\n", s);
   566       if (!(1 <= t && t <= G->nv))
   567          xerror("glp_write_maxflow: t = %d: sink node number out of ran"
   568             "ge\n", t);
   569       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   570          xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
   571             a_cap);
   572       xprintf("Writing maximum flow problem data to `%s'...\n",
   573          fname);
   574       fp = xfopen(fname, "w");
   575       if (fp == NULL)
   576       {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   577          ret = 1;
   578          goto done;
   579       }
   580       xfprintf(fp, "c %s\n",
   581          G->name == NULL ? "unknown" : G->name), count++;
   582       xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++;
   583       xfprintf(fp, "n %d s\n", s), count++;
   584       xfprintf(fp, "n %d t\n", t), count++;
   585       for (i = 1; i <= G->nv; i++)
   586       {  v = G->v[i];
   587          for (a = v->out; a != NULL; a = a->t_next)
   588          {  if (a_cap >= 0)
   589                memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
   590             else
   591                cap = 1.0;
   592             xfprintf(fp, "a %d %d %.*g\n",
   593                a->tail->i, a->head->i, DBL_DIG, cap), count++;
   594          }
   595       }
   596       xfprintf(fp, "c eof\n"), count++;
   597       xfflush(fp);
   598       if (xferror(fp))
   599       {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   600          ret = 1;
   601          goto done;
   602       }
   603       xprintf("%d lines were written\n", count);
   604       ret = 0;
   605 done: if (fp != NULL) xfclose(fp);
   606       return ret;
   607 }
   608 
   609 /***********************************************************************
   610 *  NAME
   611 *
   612 *  glp_read_asnprob - read assignment problem data in DIMACS format
   613 *
   614 *  SYNOPSIS
   615 *
   616 *  int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
   617 *     const char *fname);
   618 *
   619 *  DESCRIPTION
   620 *
   621 *  The routine glp_read_asnprob reads assignment problem data in DIMACS
   622 *  format from a text file.
   623 *
   624 *  RETURNS
   625 *
   626 *  If the operation was successful, the routine returns zero. Otherwise
   627 *  it prints an error message and returns non-zero. */
   628 
   629 int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
   630       *fname)
   631 {     struct csa _csa, *csa = &_csa;
   632       glp_vertex *v;
   633       glp_arc *a;
   634       int nv, na, n1, i, j, k, ret = 0;
   635       double cost;
   636       char *flag = NULL;
   637       if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
   638          xerror("glp_read_asnprob: v_set = %d; invalid offset\n",
   639             v_set);
   640       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   641          xerror("glp_read_asnprob: a_cost = %d; invalid offset\n",
   642             a_cost);
   643       glp_erase_graph(G, G->v_size, G->a_size);
   644       if (setjmp(csa->jump))
   645       {  ret = 1;
   646          goto done;
   647       }
   648       csa->fname = fname;
   649       csa->fp = NULL;
   650       csa->count = 0;
   651       csa->c = '\n';
   652       csa->field[0] = '\0';
   653       csa->empty = csa->nonint = 0;
   654       xprintf("Reading assignment problem data from `%s'...\n", fname);
   655       csa->fp = xfopen(fname, "r");
   656       if (csa->fp == NULL)
   657       {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   658          longjmp(csa->jump, 1);
   659       }
   660       /* read problem line */
   661       read_designator(csa);
   662       if (strcmp(csa->field, "p") != 0)
   663          error(csa, "problem line missing or invalid");
   664       read_field(csa);
   665       if (strcmp(csa->field, "asn") != 0)
   666          error(csa, "wrong problem designator; `asn' expected");
   667       read_field(csa);
   668       if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
   669          error(csa, "number of nodes missing or invalid");
   670       read_field(csa);
   671       if (!(str2int(csa->field, &na) == 0 && na >= 0))
   672          error(csa, "number of arcs missing or invalid");
   673       if (nv > 0) glp_add_vertices(G, nv);
   674       end_of_line(csa);
   675       /* read node descriptor lines */
   676       flag = xcalloc(1+nv, sizeof(char));
   677       memset(&flag[1], 0, nv * sizeof(char));
   678       n1 = 0;
   679       for (;;)
   680       {  read_designator(csa);
   681          if (strcmp(csa->field, "n") != 0) break;
   682          read_field(csa);
   683          if (str2int(csa->field, &i) != 0)
   684             error(csa, "node number missing or invalid");
   685          if (!(1 <= i && i <= nv))
   686             error(csa, "node number %d out of range", i);
   687          if (flag[i])
   688             error(csa, "duplicate descriptor of node %d", i);
   689          flag[i] = 1, n1++;
   690          end_of_line(csa);
   691       }
   692       xprintf(
   693          "Assignment problem has %d + %d = %d node%s and %d arc%s\n",
   694          n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
   695       if (v_set >= 0)
   696       {  for (i = 1; i <= nv; i++)
   697          {  v = G->v[i];
   698             k = (flag[i] ? 0 : 1);
   699             memcpy((char *)v->data + v_set, &k, sizeof(int));
   700          }
   701       }
   702       /* read arc descriptor lines */
   703       for (k = 1; k <= na; k++)
   704       {  if (k > 1) read_designator(csa);
   705          if (strcmp(csa->field, "a") != 0)
   706             error(csa, "wrong line designator; `a' expected");
   707          read_field(csa);
   708          if (str2int(csa->field, &i) != 0)
   709             error(csa, "starting node number missing or invalid");
   710          if (!(1 <= i && i <= nv))
   711             error(csa, "starting node number %d out of range", i);
   712          if (!flag[i])
   713             error(csa, "node %d cannot be a starting node", i);
   714          read_field(csa);
   715          if (str2int(csa->field, &j) != 0)
   716             error(csa, "ending node number missing or invalid");
   717          if (!(1 <= j && j <= nv))
   718             error(csa, "ending node number %d out of range", j);
   719          if (flag[j])
   720             error(csa, "node %d cannot be an ending node", j);
   721          read_field(csa);
   722          if (str2num(csa->field, &cost) != 0)
   723             error(csa, "arc cost missing or invalid");
   724          check_int(csa, cost);
   725          a = glp_add_arc(G, i, j);
   726          if (a_cost >= 0)
   727             memcpy((char *)a->data + a_cost, &cost, sizeof(double));
   728          end_of_line(csa);
   729       }
   730       xprintf("%d lines were read\n", csa->count);
   731 done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   732       if (csa->fp != NULL) xfclose(csa->fp);
   733       if (flag != NULL) xfree(flag);
   734       return ret;
   735 }
   736 
   737 /***********************************************************************
   738 *  NAME
   739 *
   740 *  glp_write_asnprob - write assignment problem data in DIMACS format
   741 *
   742 *  SYNOPSIS
   743 *
   744 *  int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
   745 *     const char *fname);
   746 *
   747 *  DESCRIPTION
   748 *
   749 *  The routine glp_write_asnprob writes assignment problem data in
   750 *  DIMACS format to a text file.
   751 *
   752 *  RETURNS
   753 *
   754 *  If the operation was successful, the routine returns zero. Otherwise
   755 *  it prints an error message and returns non-zero. */
   756 
   757 int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
   758       *fname)
   759 {     XFILE *fp;
   760       glp_vertex *v;
   761       glp_arc *a;
   762       int i, k, count = 0, ret;
   763       double cost;
   764       if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
   765          xerror("glp_write_asnprob: v_set = %d; invalid offset\n",
   766             v_set);
   767       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   768          xerror("glp_write_asnprob: a_cost = %d; invalid offset\n",
   769             a_cost);
   770       xprintf("Writing assignment problem data to `%s'...\n", fname);
   771       fp = xfopen(fname, "w");
   772       if (fp == NULL)
   773       {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   774          ret = 1;
   775          goto done;
   776       }
   777       xfprintf(fp, "c %s\n",
   778          G->name == NULL ? "unknown" : G->name), count++;
   779       xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++;
   780       for (i = 1; i <= G->nv; i++)
   781       {  v = G->v[i];
   782          if (v_set >= 0)
   783             memcpy(&k, (char *)v->data + v_set, sizeof(int));
   784          else
   785             k = (v->out != NULL ? 0 : 1);
   786          if (k == 0)
   787             xfprintf(fp, "n %d\n", i), count++;
   788       }
   789       for (i = 1; i <= G->nv; i++)
   790       {  v = G->v[i];
   791          for (a = v->out; a != NULL; a = a->t_next)
   792          {  if (a_cost >= 0)
   793                memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
   794             else
   795                cost = 1.0;
   796             xfprintf(fp, "a %d %d %.*g\n",
   797                a->tail->i, a->head->i, DBL_DIG, cost), count++;
   798          }
   799       }
   800       xfprintf(fp, "c eof\n"), count++;
   801       xfflush(fp);
   802       if (xferror(fp))
   803       {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   804          ret = 1;
   805          goto done;
   806       }
   807       xprintf("%d lines were written\n", count);
   808       ret = 0;
   809 done: if (fp != NULL) xfclose(fp);
   810       return ret;
   811 }
   812 
   813 /***********************************************************************
   814 *  NAME
   815 *
   816 *  glp_read_ccdata - read graph in DIMACS clique/coloring format
   817 *
   818 *  SYNOPSIS
   819 *
   820 *  int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
   821 *
   822 *  DESCRIPTION
   823 *
   824 *  The routine glp_read_ccdata reads an (undirected) graph in DIMACS
   825 *  clique/coloring format from a text file.
   826 *
   827 *  RETURNS
   828 *
   829 *  If the operation was successful, the routine returns zero. Otherwise
   830 *  it prints an error message and returns non-zero. */
   831 
   832 int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname)
   833 {     struct csa _csa, *csa = &_csa;
   834       glp_vertex *v;
   835       int i, j, k, nv, ne, ret = 0;
   836       double w;
   837       char *flag = NULL;
   838       if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
   839          xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n",
   840             v_wgt);
   841       glp_erase_graph(G, G->v_size, G->a_size);
   842       if (setjmp(csa->jump))
   843       {  ret = 1;
   844          goto done;
   845       }
   846       csa->fname = fname;
   847       csa->fp = NULL;
   848       csa->count = 0;
   849       csa->c = '\n';
   850       csa->field[0] = '\0';
   851       csa->empty = csa->nonint = 0;
   852       xprintf("Reading graph from `%s'...\n", fname);
   853       csa->fp = xfopen(fname, "r");
   854       if (csa->fp == NULL)
   855       {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   856          longjmp(csa->jump, 1);
   857       }
   858       /* read problem line */
   859       read_designator(csa);
   860       if (strcmp(csa->field, "p") != 0)
   861          error(csa, "problem line missing or invalid");
   862       read_field(csa);
   863       if (strcmp(csa->field, "edge") != 0)
   864          error(csa, "wrong problem designator; `edge' expected");
   865       read_field(csa);
   866       if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
   867          error(csa, "number of vertices missing or invalid");
   868       read_field(csa);
   869       if (!(str2int(csa->field, &ne) == 0 && ne >= 0))
   870          error(csa, "number of edges missing or invalid");
   871       xprintf("Graph has %d vert%s and %d edge%s\n",
   872          nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s");
   873       if (nv > 0) glp_add_vertices(G, nv);
   874       end_of_line(csa);
   875       /* read node descriptor lines */
   876       flag = xcalloc(1+nv, sizeof(char));
   877       memset(&flag[1], 0, nv * sizeof(char));
   878       if (v_wgt >= 0)
   879       {  w = 1.0;
   880          for (i = 1; i <= nv; i++)
   881          {  v = G->v[i];
   882             memcpy((char *)v->data + v_wgt, &w, sizeof(double));
   883          }
   884       }
   885       for (;;)
   886       {  read_designator(csa);
   887          if (strcmp(csa->field, "n") != 0) break;
   888          read_field(csa);
   889          if (str2int(csa->field, &i) != 0)
   890             error(csa, "vertex number missing or invalid");
   891          if (!(1 <= i && i <= nv))
   892             error(csa, "vertex number %d out of range", i);
   893          if (flag[i])
   894             error(csa, "duplicate descriptor of vertex %d", i);
   895          read_field(csa);
   896          if (str2num(csa->field, &w) != 0)
   897             error(csa, "vertex weight missing or invalid");
   898          check_int(csa, w);
   899          if (v_wgt >= 0)
   900          {  v = G->v[i];
   901             memcpy((char *)v->data + v_wgt, &w, sizeof(double));
   902          }
   903          flag[i] = 1;
   904          end_of_line(csa);
   905       }
   906       xfree(flag), flag = NULL;
   907       /* read edge descriptor lines */
   908       for (k = 1; k <= ne; k++)
   909       {  if (k > 1) read_designator(csa);
   910          if (strcmp(csa->field, "e") != 0)
   911             error(csa, "wrong line designator; `e' expected");
   912          read_field(csa);
   913          if (str2int(csa->field, &i) != 0)
   914             error(csa, "first vertex number missing or invalid");
   915          if (!(1 <= i && i <= nv))
   916             error(csa, "first vertex number %d out of range", i);
   917          read_field(csa);
   918          if (str2int(csa->field, &j) != 0)
   919             error(csa, "second vertex number missing or invalid");
   920          if (!(1 <= j && j <= nv))
   921             error(csa, "second vertex number %d out of range", j);
   922          glp_add_arc(G, i, j);
   923          end_of_line(csa);
   924       }
   925       xprintf("%d lines were read\n", csa->count);
   926 done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   927       if (csa->fp != NULL) xfclose(csa->fp);
   928       if (flag != NULL) xfree(flag);
   929       return ret;
   930 }
   931 
   932 /***********************************************************************
   933 *  NAME
   934 *
   935 *  glp_write_ccdata - write graph in DIMACS clique/coloring format
   936 *
   937 *  SYNOPSIS
   938 *
   939 *  int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
   940 *
   941 *  DESCRIPTION
   942 *
   943 *  The routine glp_write_ccdata writes the specified graph in DIMACS
   944 *  clique/coloring format to a text file.
   945 *
   946 *  RETURNS
   947 *
   948 *  If the operation was successful, the routine returns zero. Otherwise
   949 *  it prints an error message and returns non-zero. */
   950 
   951 int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname)
   952 {     XFILE *fp;
   953       glp_vertex *v;
   954       glp_arc *e;
   955       int i, count = 0, ret;
   956       double w;
   957       if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
   958          xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n",
   959             v_wgt);
   960       xprintf("Writing graph to `%s'\n", fname);
   961       fp = xfopen(fname, "w");
   962       if (fp == NULL)
   963       {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   964          ret = 1;
   965          goto done;
   966       }
   967       xfprintf(fp, "c %s\n",
   968          G->name == NULL ? "unknown" : G->name), count++;
   969       xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++;
   970       if (v_wgt >= 0)
   971       {  for (i = 1; i <= G->nv; i++)
   972          {  v = G->v[i];
   973             memcpy(&w, (char *)v->data + v_wgt, sizeof(double));
   974             if (w != 1.0)
   975                xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++;
   976          }
   977       }
   978       for (i = 1; i <= G->nv; i++)
   979       {  v = G->v[i];
   980          for (e = v->out; e != NULL; e = e->t_next)
   981             xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++;
   982       }
   983       xfprintf(fp, "c eof\n"), count++;
   984       xfflush(fp);
   985       if (xferror(fp))
   986       {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   987          ret = 1;
   988          goto done;
   989       }
   990       xprintf("%d lines were written\n", count);
   991       ret = 0;
   992 done: if (fp != NULL) xfclose(fp);
   993       return ret;
   994 }
   995 
   996 /***********************************************************************
   997 *  NAME
   998 *
   999 *  glp_read_prob - read problem data in GLPK format
  1000 *
  1001 *  SYNOPSIS
  1002 *
  1003 *  int glp_read_prob(glp_prob *P, int flags, const char *fname);
  1004 *
  1005 *  The routine glp_read_prob reads problem data in GLPK LP/MIP format
  1006 *  from a text file.
  1007 *
  1008 *  RETURNS
  1009 *
  1010 *  If the operation was successful, the routine returns zero. Otherwise
  1011 *  it prints an error message and returns non-zero. */
  1012 
  1013 int glp_read_prob(glp_prob *P, int flags, const char *fname)
  1014 {     struct csa _csa, *csa = &_csa;
  1015       int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL,
  1016          *ia = NULL, *ja = NULL;
  1017       double lb, ub, temp, *ar = NULL;
  1018       char *rf = NULL, *cf = NULL;
  1019       if (P == NULL || P->magic != GLP_PROB_MAGIC)
  1020          xerror("glp_read_prob: P = %p; invalid problem object\n",
  1021             P);
  1022       if (flags != 0)
  1023          xerror("glp_read_prob: flags = %d; invalid parameter\n",
  1024             flags);
  1025       if (fname == NULL)
  1026          xerror("glp_read_prob: fname = %d; invalid parameter\n",
  1027             fname);
  1028       glp_erase_prob(P);
  1029       if (setjmp(csa->jump))
  1030       {  ret = 1;
  1031          goto done;
  1032       }
  1033       csa->fname = fname;
  1034       csa->fp = NULL;
  1035       csa->count = 0;
  1036       csa->c = '\n';
  1037       csa->field[0] = '\0';
  1038       csa->empty = csa->nonint = 0;
  1039       xprintf("Reading problem data from `%s'...\n", fname);
  1040       csa->fp = xfopen(fname, "r");
  1041       if (csa->fp == NULL)
  1042       {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
  1043          longjmp(csa->jump, 1);
  1044       }
  1045       /* read problem line */
  1046       read_designator(csa);
  1047       if (strcmp(csa->field, "p") != 0)
  1048          error(csa, "problem line missing or invalid");
  1049       read_field(csa);
  1050       if (strcmp(csa->field, "lp") == 0)
  1051          mip = 0;
  1052       else if (strcmp(csa->field, "mip") == 0)
  1053          mip = 1;
  1054       else
  1055          error(csa, "wrong problem designator; `lp' or `mip' expected\n"
  1056             );
  1057       read_field(csa);
  1058       if (strcmp(csa->field, "min") == 0)
  1059          glp_set_obj_dir(P, GLP_MIN);
  1060       else if (strcmp(csa->field, "max") == 0)
  1061          glp_set_obj_dir(P, GLP_MAX);
  1062       else
  1063          error(csa, "objective sense missing or invalid");
  1064       read_field(csa);
  1065       if (!(str2int(csa->field, &m) == 0 && m >= 0))
  1066          error(csa, "number of rows missing or invalid");
  1067       read_field(csa);
  1068       if (!(str2int(csa->field, &n) == 0 && n >= 0))
  1069          error(csa, "number of columns missing or invalid");
  1070       read_field(csa);
  1071       if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0))
  1072          error(csa, "number of constraint coefficients missing or inval"
  1073             "id");
  1074       if (m > 0)
  1075       {  glp_add_rows(P, m);
  1076          for (i = 1; i <= m; i++)
  1077             glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0);
  1078       }
  1079       if (n > 0)
  1080       {  glp_add_cols(P, n);
  1081          for (j = 1; j <= n; j++)
  1082          {  if (!mip)
  1083                glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0);
  1084             else
  1085                glp_set_col_kind(P, j, GLP_BV);
  1086          }
  1087       }
  1088       end_of_line(csa);
  1089       /* allocate working arrays */
  1090       rf = xcalloc(1+m, sizeof(char));
  1091       memset(rf, 0, 1+m);
  1092       cf = xcalloc(1+n, sizeof(char));
  1093       memset(cf, 0, 1+n);
  1094       ln = xcalloc(1+nnz, sizeof(int));
  1095       ia = xcalloc(1+nnz, sizeof(int));
  1096       ja = xcalloc(1+nnz, sizeof(int));
  1097       ar = xcalloc(1+nnz, sizeof(double));
  1098       /* read descriptor lines */
  1099       ne = 0;
  1100       for (;;)
  1101       {  read_designator(csa);
  1102          if (strcmp(csa->field, "i") == 0)
  1103          {  /* row descriptor */
  1104             read_field(csa);
  1105             if (str2int(csa->field, &i) != 0)
  1106                error(csa, "row number missing or invalid");
  1107             if (!(1 <= i && i <= m))
  1108                error(csa, "row number out of range");
  1109             read_field(csa);
  1110             if (strcmp(csa->field, "f") == 0)
  1111                type = GLP_FR;
  1112             else if (strcmp(csa->field, "l") == 0)
  1113                type = GLP_LO;
  1114             else if (strcmp(csa->field, "u") == 0)
  1115                type = GLP_UP;
  1116             else if (strcmp(csa->field, "d") == 0)
  1117                type = GLP_DB;
  1118             else if (strcmp(csa->field, "s") == 0)
  1119                type = GLP_FX;
  1120             else
  1121                error(csa, "row type missing or invalid");
  1122             if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
  1123             {  read_field(csa);
  1124                if (str2num(csa->field, &lb) != 0)
  1125                   error(csa, "row lower bound/fixed value missing or in"
  1126                      "valid");
  1127             }
  1128             else
  1129                lb = 0.0;
  1130             if (type == GLP_UP || type == GLP_DB)
  1131             {  read_field(csa);
  1132                if (str2num(csa->field, &ub) != 0)
  1133                   error(csa, "row upper bound missing or invalid");
  1134             }
  1135             else
  1136                ub = 0.0;
  1137             if (rf[i] & 0x01)
  1138                error(csa, "duplicate row descriptor");
  1139             glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01;
  1140          }
  1141          else if (strcmp(csa->field, "j") == 0)
  1142          {  /* column descriptor */
  1143             read_field(csa);
  1144             if (str2int(csa->field, &j) != 0)
  1145                error(csa, "column number missing or invalid");
  1146             if (!(1 <= j && j <= n))
  1147                error(csa, "column number out of range");
  1148             if (!mip)
  1149                kind = GLP_CV;
  1150             else
  1151             {  read_field(csa);
  1152                if (strcmp(csa->field, "c") == 0)
  1153                   kind = GLP_CV;
  1154                else if (strcmp(csa->field, "i") == 0)
  1155                   kind = GLP_IV;
  1156                else if (strcmp(csa->field, "b") == 0)
  1157                {  kind = GLP_IV;
  1158                   type = GLP_DB, lb = 0.0, ub = 1.0;
  1159                   goto skip;
  1160                }
  1161                else
  1162                   error(csa, "column kind missing or invalid");
  1163             }
  1164             read_field(csa);
  1165             if (strcmp(csa->field, "f") == 0)
  1166                type = GLP_FR;
  1167             else if (strcmp(csa->field, "l") == 0)
  1168                type = GLP_LO;
  1169             else if (strcmp(csa->field, "u") == 0)
  1170                type = GLP_UP;
  1171             else if (strcmp(csa->field, "d") == 0)
  1172                type = GLP_DB;
  1173             else if (strcmp(csa->field, "s") == 0)
  1174                type = GLP_FX;
  1175             else
  1176                error(csa, "column type missing or invalid");
  1177             if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
  1178             {  read_field(csa);
  1179                if (str2num(csa->field, &lb) != 0)
  1180                   error(csa, "column lower bound/fixed value missing or"
  1181                      " invalid");
  1182             }
  1183             else
  1184                lb = 0.0;
  1185             if (type == GLP_UP || type == GLP_DB)
  1186             {  read_field(csa);
  1187                if (str2num(csa->field, &ub) != 0)
  1188                   error(csa, "column upper bound missing or invalid");
  1189             }
  1190             else
  1191                ub = 0.0;
  1192 skip:       if (cf[j] & 0x01)
  1193                error(csa, "duplicate column descriptor");
  1194             glp_set_col_kind(P, j, kind);
  1195             glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01;
  1196          }
  1197          else if (strcmp(csa->field, "a") == 0)
  1198          {  /* coefficient descriptor */
  1199             read_field(csa);
  1200             if (str2int(csa->field, &i) != 0)
  1201                error(csa, "row number missing or invalid");
  1202             if (!(0 <= i && i <= m))
  1203                error(csa, "row number out of range");
  1204             read_field(csa);
  1205             if (str2int(csa->field, &j) != 0)
  1206                error(csa, "column number missing or invalid");
  1207             if (!((i == 0 ? 0 : 1) <= j && j <= n))
  1208                error(csa, "column number out of range");
  1209             read_field(csa);
  1210             if (i == 0)
  1211             {  if (str2num(csa->field, &temp) != 0)
  1212                   error(csa, "objective %s missing or invalid",
  1213                      j == 0 ? "constant term" : "coefficient");
  1214                if (cf[j] & 0x10)
  1215                   error(csa, "duplicate objective %s",
  1216                      j == 0 ? "constant term" : "coefficient");
  1217                glp_set_obj_coef(P, j, temp), cf[j] |= 0x10;
  1218             }
  1219             else
  1220             {  if (str2num(csa->field, &temp) != 0)
  1221                   error(csa, "constraint coefficient missing or invalid"
  1222                      );
  1223                if (ne == nnz)
  1224                   error(csa, "too many constraint coefficient descripto"
  1225                      "rs");
  1226                ln[++ne] = csa->count;
  1227                ia[ne] = i, ja[ne] = j, ar[ne] = temp;
  1228             }
  1229          }
  1230          else if (strcmp(csa->field, "n") == 0)
  1231          {  /* symbolic name descriptor */
  1232             read_field(csa);
  1233             if (strcmp(csa->field, "p") == 0)
  1234             {  /* problem name */
  1235                read_field(csa);
  1236                if (P->name != NULL)
  1237                   error(csa, "duplicate problem name");
  1238                glp_set_prob_name(P, csa->field);
  1239             }
  1240             else if (strcmp(csa->field, "z") == 0)
  1241             {  /* objective name */
  1242                read_field(csa);
  1243                if (P->obj != NULL)
  1244                   error(csa, "duplicate objective name");
  1245                glp_set_obj_name(P, csa->field);
  1246             }
  1247             else if (strcmp(csa->field, "i") == 0)
  1248             {  /* row name */
  1249                read_field(csa);
  1250                if (str2int(csa->field, &i) != 0)
  1251                   error(csa, "row number missing or invalid");
  1252                if (!(1 <= i && i <= m))
  1253                   error(csa, "row number out of range");
  1254                read_field(csa);
  1255                if (P->row[i]->name != NULL)
  1256                   error(csa, "duplicate row name");
  1257                glp_set_row_name(P, i, csa->field);
  1258             }
  1259             else if (strcmp(csa->field, "j") == 0)
  1260             {  /* column name */
  1261                read_field(csa);
  1262                if (str2int(csa->field, &j) != 0)
  1263                   error(csa, "column number missing or invalid");
  1264                if (!(1 <= j && j <= n))
  1265                   error(csa, "column number out of range");
  1266                read_field(csa);
  1267                if (P->col[j]->name != NULL)
  1268                   error(csa, "duplicate column name");
  1269                glp_set_col_name(P, j, csa->field);
  1270             }
  1271             else
  1272                error(csa, "object designator missing or invalid");
  1273          }
  1274          else if (strcmp(csa->field, "e") == 0)
  1275             break;
  1276          else
  1277             error(csa, "line designator missing or invalid");
  1278          end_of_line(csa);
  1279       }
  1280       if (ne < nnz)
  1281          error(csa, "too few constraint coefficient descriptors");
  1282       xassert(ne == nnz);
  1283       k = glp_check_dup(m, n, ne, ia, ja);
  1284       xassert(0 <= k && k <= nnz);
  1285       if (k > 0)
  1286       {  csa->count = ln[k];
  1287          error(csa, "duplicate constraint coefficient");
  1288       }
  1289       glp_load_matrix(P, ne, ia, ja, ar);
  1290       /* print some statistics */
  1291       if (P->name != NULL)
  1292          xprintf("Problem: %s\n", P->name);
  1293       if (P->obj != NULL)
  1294          xprintf("Objective: %s\n", P->obj);
  1295       xprintf("%d row%s, %d column%s, %d non-zero%s\n",
  1296          m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ?
  1297          "" : "s");
  1298       if (glp_get_num_int(P) > 0)
  1299       {  int ni = glp_get_num_int(P);
  1300          int nb = glp_get_num_bin(P);
  1301          if (ni == 1)
  1302          {  if (nb == 0)
  1303                xprintf("One variable is integer\n");
  1304             else
  1305                xprintf("One variable is binary\n");
  1306          }
  1307          else
  1308          {  xprintf("%d integer variables, ", ni);
  1309             if (nb == 0)
  1310                xprintf("none");
  1311             else if (nb == 1)
  1312                xprintf("one");
  1313             else if (nb == ni)
  1314                xprintf("all");
  1315             else
  1316                xprintf("%d", nb);
  1317             xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
  1318          }
  1319       }
  1320       xprintf("%d lines were read\n", csa->count);
  1321       /* problem data has been successfully read */
  1322       glp_sort_matrix(P);
  1323       ret = 0;
  1324 done: if (csa->fp != NULL) xfclose(csa->fp);
  1325       if (rf != NULL) xfree(rf);
  1326       if (cf != NULL) xfree(cf);
  1327       if (ln != NULL) xfree(ln);
  1328       if (ia != NULL) xfree(ia);
  1329       if (ja != NULL) xfree(ja);
  1330       if (ar != NULL) xfree(ar);
  1331       if (ret) glp_erase_prob(P);
  1332       return ret;
  1333 }
  1334 
  1335 /***********************************************************************
  1336 *  NAME
  1337 *
  1338 *  glp_write_prob - write problem data in GLPK format
  1339 *
  1340 *  SYNOPSIS
  1341 *
  1342 *  int glp_write_prob(glp_prob *P, int flags, const char *fname);
  1343 *
  1344 *  The routine glp_write_prob writes problem data in GLPK LP/MIP format
  1345 *  to a text file.
  1346 *
  1347 *  RETURNS
  1348 *
  1349 *  If the operation was successful, the routine returns zero. Otherwise
  1350 *  it prints an error message and returns non-zero. */
  1351 
  1352 int glp_write_prob(glp_prob *P, int flags, const char *fname)
  1353 {     XFILE *fp;
  1354       GLPROW *row;
  1355       GLPCOL *col;
  1356       GLPAIJ *aij;
  1357       int mip, i, j, count, ret;
  1358       if (P == NULL || P->magic != GLP_PROB_MAGIC)
  1359          xerror("glp_write_prob: P = %p; invalid problem object\n",
  1360             P);
  1361       if (flags != 0)
  1362          xerror("glp_write_prob: flags = %d; invalid parameter\n",
  1363             flags);
  1364       if (fname == NULL)
  1365          xerror("glp_write_prob: fname = %d; invalid parameter\n",
  1366             fname);
  1367       xprintf("Writing problem data to `%s'...\n", fname);
  1368       fp = xfopen(fname, "w"), count = 0;
  1369       if (fp == NULL)
  1370       {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
  1371          ret = 1;
  1372          goto done;
  1373       }
  1374       /* write problem line */
  1375       mip = (glp_get_num_int(P) > 0);
  1376       xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip",
  1377          P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???",
  1378          P->m, P->n, P->nnz), count++;
  1379       if (P->name != NULL)
  1380          xfprintf(fp, "n p %s\n", P->name), count++;
  1381       if (P->obj != NULL)
  1382          xfprintf(fp, "n z %s\n", P->obj), count++;
  1383       /* write row descriptors */
  1384       for (i = 1; i <= P->m; i++)
  1385       {  row = P->row[i];
  1386          if (row->type == GLP_FX && row->lb == 0.0)
  1387             goto skip1;
  1388          xfprintf(fp, "i %d ", i), count++;
  1389          if (row->type == GLP_FR)
  1390             xfprintf(fp, "f\n");
  1391          else if (row->type == GLP_LO)
  1392             xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb);
  1393          else if (row->type == GLP_UP)
  1394             xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub);
  1395          else if (row->type == GLP_DB)
  1396             xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG,
  1397                   row->ub);
  1398          else if (row->type == GLP_FX)
  1399             xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb);
  1400          else
  1401             xassert(row != row);
  1402 skip1:   if (row->name != NULL)
  1403             xfprintf(fp, "n i %d %s\n", i, row->name), count++;
  1404       }
  1405       /* write column descriptors */
  1406       for (j = 1; j <= P->n; j++)
  1407       {  col = P->col[j];
  1408          if (!mip && col->type == GLP_LO && col->lb == 0.0)
  1409             goto skip2;
  1410          if (mip && col->kind == GLP_IV && col->type == GLP_DB &&
  1411              col->lb == 0.0 && col->ub == 1.0)
  1412             goto skip2;
  1413          xfprintf(fp, "j %d ", j), count++;
  1414          if (mip)
  1415          {  if (col->kind == GLP_CV)
  1416                xfprintf(fp, "c ");
  1417             else if (col->kind == GLP_IV)
  1418                xfprintf(fp, "i ");
  1419             else
  1420                xassert(col != col);
  1421          }
  1422          if (col->type == GLP_FR)
  1423             xfprintf(fp, "f\n");
  1424          else if (col->type == GLP_LO)
  1425             xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb);
  1426          else if (col->type == GLP_UP)
  1427             xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub);
  1428          else if (col->type == GLP_DB)
  1429             xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG,
  1430                   col->ub);
  1431          else if (col->type == GLP_FX)
  1432             xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb);
  1433          else
  1434             xassert(col != col);
  1435 skip2:   if (col->name != NULL)
  1436             xfprintf(fp, "n j %d %s\n", j, col->name), count++;
  1437       }
  1438       /* write objective coefficient descriptors */
  1439       if (P->c0 != 0.0)
  1440          xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++;
  1441       for (j = 1; j <= P->n; j++)
  1442       {  col = P->col[j];
  1443          if (col->coef != 0.0)
  1444             xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef),
  1445                count++;
  1446       }
  1447       /* write constraint coefficient descriptors */
  1448       for (i = 1; i <= P->m; i++)
  1449       {  row = P->row[i];
  1450          for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  1451             xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG,
  1452                aij->val), count++;
  1453       }
  1454       /* write end line */
  1455       xfprintf(fp, "e o f\n"), count++;
  1456       xfflush(fp);
  1457       if (xferror(fp))
  1458       {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
  1459          ret = 1;
  1460          goto done;
  1461       }
  1462       xprintf("%d lines were written\n", count);
  1463       ret = 0;
  1464 done: if (fp != NULL) xfclose(fp);
  1465       return ret;
  1466 }
  1467 
  1468 /* eof */