src/glpdmx.c
changeset 1 c445c931472f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/glpdmx.c	Mon Dec 06 13:09:21 2010 +0100
     1.3 @@ -0,0 +1,1468 @@
     1.4 +/* glpdmx.c (reading/writing data in DIMACS format) */
     1.5 +
     1.6 +/***********************************************************************
     1.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
     1.8 +*
     1.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
    1.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
    1.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
    1.12 +*  E-mail: <mao@gnu.org>.
    1.13 +*
    1.14 +*  GLPK is free software: you can redistribute it and/or modify it
    1.15 +*  under the terms of the GNU General Public License as published by
    1.16 +*  the Free Software Foundation, either version 3 of the License, or
    1.17 +*  (at your option) any later version.
    1.18 +*
    1.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
    1.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    1.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    1.22 +*  License for more details.
    1.23 +*
    1.24 +*  You should have received a copy of the GNU General Public License
    1.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
    1.26 +***********************************************************************/
    1.27 +
    1.28 +#define _GLPSTD_STDIO
    1.29 +#include "glpapi.h"
    1.30 +
    1.31 +struct csa
    1.32 +{     /* common storage area */
    1.33 +      jmp_buf jump;
    1.34 +      /* label for go to in case of error */
    1.35 +      const char *fname;
    1.36 +      /* name of input text file */
    1.37 +      XFILE *fp;
    1.38 +      /* stream assigned to input text file */
    1.39 +      int count;
    1.40 +      /* line count */
    1.41 +      int c;
    1.42 +      /* current character */
    1.43 +      char field[255+1];
    1.44 +      /* data field */
    1.45 +      int empty;
    1.46 +      /* warning 'empty line ignored' was printed */
    1.47 +      int nonint;
    1.48 +      /* warning 'non-integer data detected' was printed */
    1.49 +};
    1.50 +
    1.51 +static void error(struct csa *csa, const char *fmt, ...)
    1.52 +{     /* print error message and terminate processing */
    1.53 +      va_list arg;
    1.54 +      xprintf("%s:%d: error: ", csa->fname, csa->count);
    1.55 +      va_start(arg, fmt);
    1.56 +      xvprintf(fmt, arg);
    1.57 +      va_end(arg);
    1.58 +      xprintf("\n");
    1.59 +      longjmp(csa->jump, 1);
    1.60 +      /* no return */
    1.61 +}
    1.62 +
    1.63 +static void warning(struct csa *csa, const char *fmt, ...)
    1.64 +{     /* print warning message and continue processing */
    1.65 +      va_list arg;
    1.66 +      xprintf("%s:%d: warning: ", csa->fname, csa->count);
    1.67 +      va_start(arg, fmt);
    1.68 +      xvprintf(fmt, arg);
    1.69 +      va_end(arg);
    1.70 +      xprintf("\n");
    1.71 +      return;
    1.72 +}
    1.73 +
    1.74 +static void read_char(struct csa *csa)
    1.75 +{     /* read character from input text file */
    1.76 +      int c;
    1.77 +      if (csa->c == '\n') csa->count++;
    1.78 +      c = xfgetc(csa->fp);
    1.79 +      if (c < 0)
    1.80 +      {  if (xferror(csa->fp))
    1.81 +            error(csa, "read error - %s", xerrmsg());
    1.82 +         else if (csa->c == '\n')
    1.83 +            error(csa, "unexpected end of file");
    1.84 +         else
    1.85 +         {  warning(csa, "missing final end of line");
    1.86 +            c = '\n';
    1.87 +         }
    1.88 +      }
    1.89 +      else if (c == '\n')
    1.90 +         ;
    1.91 +      else if (isspace(c))
    1.92 +         c = ' ';
    1.93 +      else if (iscntrl(c))
    1.94 +         error(csa, "invalid control character 0x%02X", c);
    1.95 +      csa->c = c;
    1.96 +      return;
    1.97 +}
    1.98 +
    1.99 +static void read_designator(struct csa *csa)
   1.100 +{     /* read one-character line designator */
   1.101 +      xassert(csa->c == '\n');
   1.102 +      read_char(csa);
   1.103 +      for (;;)
   1.104 +      {  /* skip preceding white-space characters */
   1.105 +         while (csa->c == ' ')
   1.106 +            read_char(csa);
   1.107 +         if (csa->c == '\n')
   1.108 +         {  /* ignore empty line */
   1.109 +            if (!csa->empty)
   1.110 +            {  warning(csa, "empty line ignored");
   1.111 +               csa->empty = 1;
   1.112 +            }
   1.113 +            read_char(csa);
   1.114 +         }
   1.115 +         else if (csa->c == 'c')
   1.116 +         {  /* skip comment line */
   1.117 +            while (csa->c != '\n')
   1.118 +               read_char(csa);
   1.119 +            read_char(csa);
   1.120 +         }
   1.121 +         else
   1.122 +         {  /* hmm... looks like a line designator */
   1.123 +            csa->field[0] = (char)csa->c, csa->field[1] = '\0';
   1.124 +            /* check that it is followed by a white-space character */
   1.125 +            read_char(csa);
   1.126 +            if (!(csa->c == ' ' || csa->c == '\n'))
   1.127 +               error(csa, "line designator missing or invalid");
   1.128 +            break;
   1.129 +         }
   1.130 +      }
   1.131 +      return;
   1.132 +}
   1.133 +
   1.134 +static void read_field(struct csa *csa)
   1.135 +{     /* read data field */
   1.136 +      int len = 0;
   1.137 +      /* skip preceding white-space characters */
   1.138 +      while (csa->c == ' ')
   1.139 +         read_char(csa);
   1.140 +      /* scan data field */
   1.141 +      if (csa->c == '\n')
   1.142 +         error(csa, "unexpected end of line");
   1.143 +      while (!(csa->c == ' ' || csa->c == '\n'))
   1.144 +      {  if (len == sizeof(csa->field)-1)
   1.145 +            error(csa, "data field `%.15s...' too long", csa->field);
   1.146 +         csa->field[len++] = (char)csa->c;
   1.147 +         read_char(csa);
   1.148 +      }
   1.149 +      csa->field[len] = '\0';
   1.150 +      return;
   1.151 +}
   1.152 +
   1.153 +static void end_of_line(struct csa *csa)
   1.154 +{     /* skip white-space characters until end of line */
   1.155 +      while (csa->c == ' ')
   1.156 +         read_char(csa);
   1.157 +      if (csa->c != '\n')
   1.158 +         error(csa, "too many data fields specified");
   1.159 +      return;
   1.160 +}
   1.161 +
   1.162 +static void check_int(struct csa *csa, double num)
   1.163 +{     /* print a warning if non-integer data are detected */
   1.164 +      if (!csa->nonint && num != floor(num))
   1.165 +      {  warning(csa, "non-integer data detected");
   1.166 +         csa->nonint = 1;
   1.167 +      }
   1.168 +      return;
   1.169 +}
   1.170 +
   1.171 +/***********************************************************************
   1.172 +*  NAME
   1.173 +*
   1.174 +*  glp_read_mincost - read min-cost flow problem data in DIMACS format
   1.175 +*
   1.176 +*  SYNOPSIS
   1.177 +*
   1.178 +*  int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   1.179 +*     int a_cost, const char *fname);
   1.180 +*
   1.181 +*  DESCRIPTION
   1.182 +*
   1.183 +*  The routine glp_read_mincost reads minimum cost flow problem data in
   1.184 +*  DIMACS format from a text file.
   1.185 +*
   1.186 +*  RETURNS
   1.187 +*
   1.188 +*  If the operation was successful, the routine returns zero. Otherwise
   1.189 +*  it prints an error message and returns non-zero. */
   1.190 +
   1.191 +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   1.192 +      int a_cost, const char *fname)
   1.193 +{     struct csa _csa, *csa = &_csa;
   1.194 +      glp_vertex *v;
   1.195 +      glp_arc *a;
   1.196 +      int i, j, k, nv, na, ret = 0;
   1.197 +      double rhs, low, cap, cost;
   1.198 +      char *flag = NULL;
   1.199 +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
   1.200 +         xerror("glp_read_mincost: v_rhs = %d; invalid offset\n",
   1.201 +            v_rhs);
   1.202 +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
   1.203 +         xerror("glp_read_mincost: a_low = %d; invalid offset\n",
   1.204 +            a_low);
   1.205 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   1.206 +         xerror("glp_read_mincost: a_cap = %d; invalid offset\n",
   1.207 +            a_cap);
   1.208 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   1.209 +         xerror("glp_read_mincost: a_cost = %d; invalid offset\n",
   1.210 +            a_cost);
   1.211 +      glp_erase_graph(G, G->v_size, G->a_size);
   1.212 +      if (setjmp(csa->jump))
   1.213 +      {  ret = 1;
   1.214 +         goto done;
   1.215 +      }
   1.216 +      csa->fname = fname;
   1.217 +      csa->fp = NULL;
   1.218 +      csa->count = 0;
   1.219 +      csa->c = '\n';
   1.220 +      csa->field[0] = '\0';
   1.221 +      csa->empty = csa->nonint = 0;
   1.222 +      xprintf("Reading min-cost flow problem data from `%s'...\n",
   1.223 +         fname);
   1.224 +      csa->fp = xfopen(fname, "r");
   1.225 +      if (csa->fp == NULL)
   1.226 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   1.227 +         longjmp(csa->jump, 1);
   1.228 +      }
   1.229 +      /* read problem line */
   1.230 +      read_designator(csa);
   1.231 +      if (strcmp(csa->field, "p") != 0)
   1.232 +         error(csa, "problem line missing or invalid");
   1.233 +      read_field(csa);
   1.234 +      if (strcmp(csa->field, "min") != 0)
   1.235 +         error(csa, "wrong problem designator; `min' expected");
   1.236 +      read_field(csa);
   1.237 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
   1.238 +         error(csa, "number of nodes missing or invalid");
   1.239 +      read_field(csa);
   1.240 +      if (!(str2int(csa->field, &na) == 0 && na >= 0))
   1.241 +         error(csa, "number of arcs missing or invalid");
   1.242 +      xprintf("Flow network has %d node%s and %d arc%s\n",
   1.243 +         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
   1.244 +      if (nv > 0) glp_add_vertices(G, nv);
   1.245 +      end_of_line(csa);
   1.246 +      /* read node descriptor lines */
   1.247 +      flag = xcalloc(1+nv, sizeof(char));
   1.248 +      memset(&flag[1], 0, nv * sizeof(char));
   1.249 +      if (v_rhs >= 0)
   1.250 +      {  rhs = 0.0;
   1.251 +         for (i = 1; i <= nv; i++)
   1.252 +         {  v = G->v[i];
   1.253 +            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
   1.254 +         }
   1.255 +      }
   1.256 +      for (;;)
   1.257 +      {  read_designator(csa);
   1.258 +         if (strcmp(csa->field, "n") != 0) break;
   1.259 +         read_field(csa);
   1.260 +         if (str2int(csa->field, &i) != 0)
   1.261 +            error(csa, "node number missing or invalid");
   1.262 +         if (!(1 <= i && i <= nv))
   1.263 +            error(csa, "node number %d out of range", i);
   1.264 +         if (flag[i])
   1.265 +            error(csa, "duplicate descriptor of node %d", i);
   1.266 +         read_field(csa);
   1.267 +         if (str2num(csa->field, &rhs) != 0)
   1.268 +            error(csa, "node supply/demand missing or invalid");
   1.269 +         check_int(csa, rhs);
   1.270 +         if (v_rhs >= 0)
   1.271 +         {  v = G->v[i];
   1.272 +            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
   1.273 +         }
   1.274 +         flag[i] = 1;
   1.275 +         end_of_line(csa);
   1.276 +      }
   1.277 +      xfree(flag), flag = NULL;
   1.278 +      /* read arc descriptor lines */
   1.279 +      for (k = 1; k <= na; k++)
   1.280 +      {  if (k > 1) read_designator(csa);
   1.281 +         if (strcmp(csa->field, "a") != 0)
   1.282 +            error(csa, "wrong line designator; `a' expected");
   1.283 +         read_field(csa);
   1.284 +         if (str2int(csa->field, &i) != 0)
   1.285 +            error(csa, "starting node number missing or invalid");
   1.286 +         if (!(1 <= i && i <= nv))
   1.287 +            error(csa, "starting node number %d out of range", i);
   1.288 +         read_field(csa);
   1.289 +         if (str2int(csa->field, &j) != 0)
   1.290 +            error(csa, "ending node number missing or invalid");
   1.291 +         if (!(1 <= j && j <= nv))
   1.292 +            error(csa, "ending node number %d out of range", j);
   1.293 +         read_field(csa);
   1.294 +         if (!(str2num(csa->field, &low) == 0 && low >= 0.0))
   1.295 +            error(csa, "lower bound of arc flow missing or invalid");
   1.296 +         check_int(csa, low);
   1.297 +         read_field(csa);
   1.298 +         if (!(str2num(csa->field, &cap) == 0 && cap >= low))
   1.299 +            error(csa, "upper bound of arc flow missing or invalid");
   1.300 +         check_int(csa, cap);
   1.301 +         read_field(csa);
   1.302 +         if (str2num(csa->field, &cost) != 0)
   1.303 +            error(csa, "per-unit cost of arc flow missing or invalid");
   1.304 +         check_int(csa, cost);
   1.305 +         a = glp_add_arc(G, i, j);
   1.306 +         if (a_low >= 0)
   1.307 +            memcpy((char *)a->data + a_low, &low, sizeof(double));
   1.308 +         if (a_cap >= 0)
   1.309 +            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
   1.310 +         if (a_cost >= 0)
   1.311 +            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
   1.312 +         end_of_line(csa);
   1.313 +      }
   1.314 +      xprintf("%d lines were read\n", csa->count);
   1.315 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   1.316 +      if (csa->fp != NULL) xfclose(csa->fp);
   1.317 +      if (flag != NULL) xfree(flag);
   1.318 +      return ret;
   1.319 +}
   1.320 +
   1.321 +/***********************************************************************
   1.322 +*  NAME
   1.323 +*
   1.324 +*  glp_write_mincost - write min-cost flow problem data in DIMACS format
   1.325 +*
   1.326 +*  SYNOPSIS
   1.327 +*
   1.328 +*  int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   1.329 +*     int a_cost, const char *fname);
   1.330 +*
   1.331 +*  DESCRIPTION
   1.332 +*
   1.333 +*  The routine glp_write_mincost writes minimum cost flow problem data
   1.334 +*  in DIMACS format to a text file.
   1.335 +*
   1.336 +*  RETURNS
   1.337 +*
   1.338 +*  If the operation was successful, the routine returns zero. Otherwise
   1.339 +*  it prints an error message and returns non-zero. */
   1.340 +
   1.341 +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
   1.342 +      int a_cost, const char *fname)
   1.343 +{     XFILE *fp;
   1.344 +      glp_vertex *v;
   1.345 +      glp_arc *a;
   1.346 +      int i, count = 0, ret;
   1.347 +      double rhs, low, cap, cost;
   1.348 +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
   1.349 +         xerror("glp_write_mincost: v_rhs = %d; invalid offset\n",
   1.350 +            v_rhs);
   1.351 +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
   1.352 +         xerror("glp_write_mincost: a_low = %d; invalid offset\n",
   1.353 +            a_low);
   1.354 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   1.355 +         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
   1.356 +            a_cap);
   1.357 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   1.358 +         xerror("glp_write_mincost: a_cost = %d; invalid offset\n",
   1.359 +            a_cost);
   1.360 +      xprintf("Writing min-cost flow problem data to `%s'...\n",
   1.361 +         fname);
   1.362 +      fp = xfopen(fname, "w");
   1.363 +      if (fp == NULL)
   1.364 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   1.365 +         ret = 1;
   1.366 +         goto done;
   1.367 +      }
   1.368 +      xfprintf(fp, "c %s\n",
   1.369 +         G->name == NULL ? "unknown" : G->name), count++;
   1.370 +      xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++;
   1.371 +      if (v_rhs >= 0)
   1.372 +      {  for (i = 1; i <= G->nv; i++)
   1.373 +         {  v = G->v[i];
   1.374 +            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
   1.375 +            if (rhs != 0.0)
   1.376 +               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++;
   1.377 +         }
   1.378 +      }
   1.379 +      for (i = 1; i <= G->nv; i++)
   1.380 +      {  v = G->v[i];
   1.381 +         for (a = v->out; a != NULL; a = a->t_next)
   1.382 +         {  if (a_low >= 0)
   1.383 +               memcpy(&low, (char *)a->data + a_low, sizeof(double));
   1.384 +            else
   1.385 +               low = 0.0;
   1.386 +            if (a_cap >= 0)
   1.387 +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
   1.388 +            else
   1.389 +               cap = 1.0;
   1.390 +            if (a_cost >= 0)
   1.391 +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
   1.392 +            else
   1.393 +               cost = 0.0;
   1.394 +            xfprintf(fp, "a %d %d %.*g %.*g %.*g\n",
   1.395 +               a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap,
   1.396 +               DBL_DIG, cost), count++;
   1.397 +         }
   1.398 +      }
   1.399 +      xfprintf(fp, "c eof\n"), count++;
   1.400 +      xfflush(fp);
   1.401 +      if (xferror(fp))
   1.402 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   1.403 +         ret = 1;
   1.404 +         goto done;
   1.405 +      }
   1.406 +      xprintf("%d lines were written\n", count);
   1.407 +      ret = 0;
   1.408 +done: if (fp != NULL) xfclose(fp);
   1.409 +      return ret;
   1.410 +}
   1.411 +
   1.412 +/***********************************************************************
   1.413 +*  NAME
   1.414 +*
   1.415 +*  glp_read_maxflow - read maximum flow problem data in DIMACS format
   1.416 +*
   1.417 +*  SYNOPSIS
   1.418 +*
   1.419 +*  int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
   1.420 +*     const char *fname);
   1.421 +*
   1.422 +*  DESCRIPTION
   1.423 +*
   1.424 +*  The routine glp_read_maxflow reads maximum flow problem data in
   1.425 +*  DIMACS format from a text file.
   1.426 +*
   1.427 +*  RETURNS
   1.428 +*
   1.429 +*  If the operation was successful, the routine returns zero. Otherwise
   1.430 +*  it prints an error message and returns non-zero. */
   1.431 +
   1.432 +int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap,
   1.433 +      const char *fname)
   1.434 +{     struct csa _csa, *csa = &_csa;
   1.435 +      glp_arc *a;
   1.436 +      int i, j, k, s, t, nv, na, ret = 0;
   1.437 +      double cap;
   1.438 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   1.439 +         xerror("glp_read_maxflow: a_cap = %d; invalid offset\n",
   1.440 +            a_cap);
   1.441 +      glp_erase_graph(G, G->v_size, G->a_size);
   1.442 +      if (setjmp(csa->jump))
   1.443 +      {  ret = 1;
   1.444 +         goto done;
   1.445 +      }
   1.446 +      csa->fname = fname;
   1.447 +      csa->fp = NULL;
   1.448 +      csa->count = 0;
   1.449 +      csa->c = '\n';
   1.450 +      csa->field[0] = '\0';
   1.451 +      csa->empty = csa->nonint = 0;
   1.452 +      xprintf("Reading maximum flow problem data from `%s'...\n",
   1.453 +         fname);
   1.454 +      csa->fp = xfopen(fname, "r");
   1.455 +      if (csa->fp == NULL)
   1.456 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   1.457 +         longjmp(csa->jump, 1);
   1.458 +      }
   1.459 +      /* read problem line */
   1.460 +      read_designator(csa);
   1.461 +      if (strcmp(csa->field, "p") != 0)
   1.462 +         error(csa, "problem line missing or invalid");
   1.463 +      read_field(csa);
   1.464 +      if (strcmp(csa->field, "max") != 0)
   1.465 +         error(csa, "wrong problem designator; `max' expected");
   1.466 +      read_field(csa);
   1.467 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 2))
   1.468 +         error(csa, "number of nodes missing or invalid");
   1.469 +      read_field(csa);
   1.470 +      if (!(str2int(csa->field, &na) == 0 && na >= 0))
   1.471 +         error(csa, "number of arcs missing or invalid");
   1.472 +      xprintf("Flow network has %d node%s and %d arc%s\n",
   1.473 +         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
   1.474 +      if (nv > 0) glp_add_vertices(G, nv);
   1.475 +      end_of_line(csa);
   1.476 +      /* read node descriptor lines */
   1.477 +      s = t = 0;
   1.478 +      for (;;)
   1.479 +      {  read_designator(csa);
   1.480 +         if (strcmp(csa->field, "n") != 0) break;
   1.481 +         read_field(csa);
   1.482 +         if (str2int(csa->field, &i) != 0)
   1.483 +            error(csa, "node number missing or invalid");
   1.484 +         if (!(1 <= i && i <= nv))
   1.485 +            error(csa, "node number %d out of range", i);
   1.486 +         read_field(csa);
   1.487 +         if (strcmp(csa->field, "s") == 0)
   1.488 +         {  if (s > 0)
   1.489 +               error(csa, "only one source node allowed");
   1.490 +            s = i;
   1.491 +         }
   1.492 +         else if (strcmp(csa->field, "t") == 0)
   1.493 +         {  if (t > 0)
   1.494 +               error(csa, "only one sink node allowed");
   1.495 +            t = i;
   1.496 +         }
   1.497 +         else
   1.498 +            error(csa, "wrong node designator; `s' or `t' expected");
   1.499 +         if (s > 0 && s == t)
   1.500 +            error(csa, "source and sink nodes must be distinct");
   1.501 +         end_of_line(csa);
   1.502 +      }
   1.503 +      if (s == 0)
   1.504 +         error(csa, "source node descriptor missing\n");
   1.505 +      if (t == 0)
   1.506 +         error(csa, "sink node descriptor missing\n");
   1.507 +      if (_s != NULL) *_s = s;
   1.508 +      if (_t != NULL) *_t = t;
   1.509 +      /* read arc descriptor lines */
   1.510 +      for (k = 1; k <= na; k++)
   1.511 +      {  if (k > 1) read_designator(csa);
   1.512 +         if (strcmp(csa->field, "a") != 0)
   1.513 +            error(csa, "wrong line designator; `a' expected");
   1.514 +         read_field(csa);
   1.515 +         if (str2int(csa->field, &i) != 0)
   1.516 +            error(csa, "starting node number missing or invalid");
   1.517 +         if (!(1 <= i && i <= nv))
   1.518 +            error(csa, "starting node number %d out of range", i);
   1.519 +         read_field(csa);
   1.520 +         if (str2int(csa->field, &j) != 0)
   1.521 +            error(csa, "ending node number missing or invalid");
   1.522 +         if (!(1 <= j && j <= nv))
   1.523 +            error(csa, "ending node number %d out of range", j);
   1.524 +         read_field(csa);
   1.525 +         if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0))
   1.526 +            error(csa, "arc capacity missing or invalid");
   1.527 +         check_int(csa, cap);
   1.528 +         a = glp_add_arc(G, i, j);
   1.529 +         if (a_cap >= 0)
   1.530 +            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
   1.531 +         end_of_line(csa);
   1.532 +      }
   1.533 +      xprintf("%d lines were read\n", csa->count);
   1.534 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   1.535 +      if (csa->fp != NULL) xfclose(csa->fp);
   1.536 +      return ret;
   1.537 +}
   1.538 +
   1.539 +/***********************************************************************
   1.540 +*  NAME
   1.541 +*
   1.542 +*  glp_write_maxflow - write maximum flow problem data in DIMACS format
   1.543 +*
   1.544 +*  SYNOPSIS
   1.545 +*
   1.546 +*  int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
   1.547 +*     const char *fname);
   1.548 +*
   1.549 +*  DESCRIPTION
   1.550 +*
   1.551 +*  The routine glp_write_maxflow writes maximum flow problem data in
   1.552 +*  DIMACS format to a text file.
   1.553 +*
   1.554 +*  RETURNS
   1.555 +*
   1.556 +*  If the operation was successful, the routine returns zero. Otherwise
   1.557 +*  it prints an error message and returns non-zero. */
   1.558 +
   1.559 +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
   1.560 +      const char *fname)
   1.561 +{     XFILE *fp;
   1.562 +      glp_vertex *v;
   1.563 +      glp_arc *a;
   1.564 +      int i, count = 0, ret;
   1.565 +      double cap;
   1.566 +      if (!(1 <= s && s <= G->nv))
   1.567 +         xerror("glp_write_maxflow: s = %d; source node number out of r"
   1.568 +            "ange\n", s);
   1.569 +      if (!(1 <= t && t <= G->nv))
   1.570 +         xerror("glp_write_maxflow: t = %d: sink node number out of ran"
   1.571 +            "ge\n", t);
   1.572 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
   1.573 +         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
   1.574 +            a_cap);
   1.575 +      xprintf("Writing maximum flow problem data to `%s'...\n",
   1.576 +         fname);
   1.577 +      fp = xfopen(fname, "w");
   1.578 +      if (fp == NULL)
   1.579 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   1.580 +         ret = 1;
   1.581 +         goto done;
   1.582 +      }
   1.583 +      xfprintf(fp, "c %s\n",
   1.584 +         G->name == NULL ? "unknown" : G->name), count++;
   1.585 +      xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++;
   1.586 +      xfprintf(fp, "n %d s\n", s), count++;
   1.587 +      xfprintf(fp, "n %d t\n", t), count++;
   1.588 +      for (i = 1; i <= G->nv; i++)
   1.589 +      {  v = G->v[i];
   1.590 +         for (a = v->out; a != NULL; a = a->t_next)
   1.591 +         {  if (a_cap >= 0)
   1.592 +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
   1.593 +            else
   1.594 +               cap = 1.0;
   1.595 +            xfprintf(fp, "a %d %d %.*g\n",
   1.596 +               a->tail->i, a->head->i, DBL_DIG, cap), count++;
   1.597 +         }
   1.598 +      }
   1.599 +      xfprintf(fp, "c eof\n"), count++;
   1.600 +      xfflush(fp);
   1.601 +      if (xferror(fp))
   1.602 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   1.603 +         ret = 1;
   1.604 +         goto done;
   1.605 +      }
   1.606 +      xprintf("%d lines were written\n", count);
   1.607 +      ret = 0;
   1.608 +done: if (fp != NULL) xfclose(fp);
   1.609 +      return ret;
   1.610 +}
   1.611 +
   1.612 +/***********************************************************************
   1.613 +*  NAME
   1.614 +*
   1.615 +*  glp_read_asnprob - read assignment problem data in DIMACS format
   1.616 +*
   1.617 +*  SYNOPSIS
   1.618 +*
   1.619 +*  int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
   1.620 +*     const char *fname);
   1.621 +*
   1.622 +*  DESCRIPTION
   1.623 +*
   1.624 +*  The routine glp_read_asnprob reads assignment problem data in DIMACS
   1.625 +*  format from a text file.
   1.626 +*
   1.627 +*  RETURNS
   1.628 +*
   1.629 +*  If the operation was successful, the routine returns zero. Otherwise
   1.630 +*  it prints an error message and returns non-zero. */
   1.631 +
   1.632 +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
   1.633 +      *fname)
   1.634 +{     struct csa _csa, *csa = &_csa;
   1.635 +      glp_vertex *v;
   1.636 +      glp_arc *a;
   1.637 +      int nv, na, n1, i, j, k, ret = 0;
   1.638 +      double cost;
   1.639 +      char *flag = NULL;
   1.640 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
   1.641 +         xerror("glp_read_asnprob: v_set = %d; invalid offset\n",
   1.642 +            v_set);
   1.643 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   1.644 +         xerror("glp_read_asnprob: a_cost = %d; invalid offset\n",
   1.645 +            a_cost);
   1.646 +      glp_erase_graph(G, G->v_size, G->a_size);
   1.647 +      if (setjmp(csa->jump))
   1.648 +      {  ret = 1;
   1.649 +         goto done;
   1.650 +      }
   1.651 +      csa->fname = fname;
   1.652 +      csa->fp = NULL;
   1.653 +      csa->count = 0;
   1.654 +      csa->c = '\n';
   1.655 +      csa->field[0] = '\0';
   1.656 +      csa->empty = csa->nonint = 0;
   1.657 +      xprintf("Reading assignment problem data from `%s'...\n", fname);
   1.658 +      csa->fp = xfopen(fname, "r");
   1.659 +      if (csa->fp == NULL)
   1.660 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   1.661 +         longjmp(csa->jump, 1);
   1.662 +      }
   1.663 +      /* read problem line */
   1.664 +      read_designator(csa);
   1.665 +      if (strcmp(csa->field, "p") != 0)
   1.666 +         error(csa, "problem line missing or invalid");
   1.667 +      read_field(csa);
   1.668 +      if (strcmp(csa->field, "asn") != 0)
   1.669 +         error(csa, "wrong problem designator; `asn' expected");
   1.670 +      read_field(csa);
   1.671 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
   1.672 +         error(csa, "number of nodes missing or invalid");
   1.673 +      read_field(csa);
   1.674 +      if (!(str2int(csa->field, &na) == 0 && na >= 0))
   1.675 +         error(csa, "number of arcs missing or invalid");
   1.676 +      if (nv > 0) glp_add_vertices(G, nv);
   1.677 +      end_of_line(csa);
   1.678 +      /* read node descriptor lines */
   1.679 +      flag = xcalloc(1+nv, sizeof(char));
   1.680 +      memset(&flag[1], 0, nv * sizeof(char));
   1.681 +      n1 = 0;
   1.682 +      for (;;)
   1.683 +      {  read_designator(csa);
   1.684 +         if (strcmp(csa->field, "n") != 0) break;
   1.685 +         read_field(csa);
   1.686 +         if (str2int(csa->field, &i) != 0)
   1.687 +            error(csa, "node number missing or invalid");
   1.688 +         if (!(1 <= i && i <= nv))
   1.689 +            error(csa, "node number %d out of range", i);
   1.690 +         if (flag[i])
   1.691 +            error(csa, "duplicate descriptor of node %d", i);
   1.692 +         flag[i] = 1, n1++;
   1.693 +         end_of_line(csa);
   1.694 +      }
   1.695 +      xprintf(
   1.696 +         "Assignment problem has %d + %d = %d node%s and %d arc%s\n",
   1.697 +         n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
   1.698 +      if (v_set >= 0)
   1.699 +      {  for (i = 1; i <= nv; i++)
   1.700 +         {  v = G->v[i];
   1.701 +            k = (flag[i] ? 0 : 1);
   1.702 +            memcpy((char *)v->data + v_set, &k, sizeof(int));
   1.703 +         }
   1.704 +      }
   1.705 +      /* read arc descriptor lines */
   1.706 +      for (k = 1; k <= na; k++)
   1.707 +      {  if (k > 1) read_designator(csa);
   1.708 +         if (strcmp(csa->field, "a") != 0)
   1.709 +            error(csa, "wrong line designator; `a' expected");
   1.710 +         read_field(csa);
   1.711 +         if (str2int(csa->field, &i) != 0)
   1.712 +            error(csa, "starting node number missing or invalid");
   1.713 +         if (!(1 <= i && i <= nv))
   1.714 +            error(csa, "starting node number %d out of range", i);
   1.715 +         if (!flag[i])
   1.716 +            error(csa, "node %d cannot be a starting node", i);
   1.717 +         read_field(csa);
   1.718 +         if (str2int(csa->field, &j) != 0)
   1.719 +            error(csa, "ending node number missing or invalid");
   1.720 +         if (!(1 <= j && j <= nv))
   1.721 +            error(csa, "ending node number %d out of range", j);
   1.722 +         if (flag[j])
   1.723 +            error(csa, "node %d cannot be an ending node", j);
   1.724 +         read_field(csa);
   1.725 +         if (str2num(csa->field, &cost) != 0)
   1.726 +            error(csa, "arc cost missing or invalid");
   1.727 +         check_int(csa, cost);
   1.728 +         a = glp_add_arc(G, i, j);
   1.729 +         if (a_cost >= 0)
   1.730 +            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
   1.731 +         end_of_line(csa);
   1.732 +      }
   1.733 +      xprintf("%d lines were read\n", csa->count);
   1.734 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   1.735 +      if (csa->fp != NULL) xfclose(csa->fp);
   1.736 +      if (flag != NULL) xfree(flag);
   1.737 +      return ret;
   1.738 +}
   1.739 +
   1.740 +/***********************************************************************
   1.741 +*  NAME
   1.742 +*
   1.743 +*  glp_write_asnprob - write assignment problem data in DIMACS format
   1.744 +*
   1.745 +*  SYNOPSIS
   1.746 +*
   1.747 +*  int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
   1.748 +*     const char *fname);
   1.749 +*
   1.750 +*  DESCRIPTION
   1.751 +*
   1.752 +*  The routine glp_write_asnprob writes assignment problem data in
   1.753 +*  DIMACS format to a text file.
   1.754 +*
   1.755 +*  RETURNS
   1.756 +*
   1.757 +*  If the operation was successful, the routine returns zero. Otherwise
   1.758 +*  it prints an error message and returns non-zero. */
   1.759 +
   1.760 +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
   1.761 +      *fname)
   1.762 +{     XFILE *fp;
   1.763 +      glp_vertex *v;
   1.764 +      glp_arc *a;
   1.765 +      int i, k, count = 0, ret;
   1.766 +      double cost;
   1.767 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
   1.768 +         xerror("glp_write_asnprob: v_set = %d; invalid offset\n",
   1.769 +            v_set);
   1.770 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
   1.771 +         xerror("glp_write_asnprob: a_cost = %d; invalid offset\n",
   1.772 +            a_cost);
   1.773 +      xprintf("Writing assignment problem data to `%s'...\n", fname);
   1.774 +      fp = xfopen(fname, "w");
   1.775 +      if (fp == NULL)
   1.776 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   1.777 +         ret = 1;
   1.778 +         goto done;
   1.779 +      }
   1.780 +      xfprintf(fp, "c %s\n",
   1.781 +         G->name == NULL ? "unknown" : G->name), count++;
   1.782 +      xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++;
   1.783 +      for (i = 1; i <= G->nv; i++)
   1.784 +      {  v = G->v[i];
   1.785 +         if (v_set >= 0)
   1.786 +            memcpy(&k, (char *)v->data + v_set, sizeof(int));
   1.787 +         else
   1.788 +            k = (v->out != NULL ? 0 : 1);
   1.789 +         if (k == 0)
   1.790 +            xfprintf(fp, "n %d\n", i), count++;
   1.791 +      }
   1.792 +      for (i = 1; i <= G->nv; i++)
   1.793 +      {  v = G->v[i];
   1.794 +         for (a = v->out; a != NULL; a = a->t_next)
   1.795 +         {  if (a_cost >= 0)
   1.796 +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
   1.797 +            else
   1.798 +               cost = 1.0;
   1.799 +            xfprintf(fp, "a %d %d %.*g\n",
   1.800 +               a->tail->i, a->head->i, DBL_DIG, cost), count++;
   1.801 +         }
   1.802 +      }
   1.803 +      xfprintf(fp, "c eof\n"), count++;
   1.804 +      xfflush(fp);
   1.805 +      if (xferror(fp))
   1.806 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   1.807 +         ret = 1;
   1.808 +         goto done;
   1.809 +      }
   1.810 +      xprintf("%d lines were written\n", count);
   1.811 +      ret = 0;
   1.812 +done: if (fp != NULL) xfclose(fp);
   1.813 +      return ret;
   1.814 +}
   1.815 +
   1.816 +/***********************************************************************
   1.817 +*  NAME
   1.818 +*
   1.819 +*  glp_read_ccdata - read graph in DIMACS clique/coloring format
   1.820 +*
   1.821 +*  SYNOPSIS
   1.822 +*
   1.823 +*  int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
   1.824 +*
   1.825 +*  DESCRIPTION
   1.826 +*
   1.827 +*  The routine glp_read_ccdata reads an (undirected) graph in DIMACS
   1.828 +*  clique/coloring format from a text file.
   1.829 +*
   1.830 +*  RETURNS
   1.831 +*
   1.832 +*  If the operation was successful, the routine returns zero. Otherwise
   1.833 +*  it prints an error message and returns non-zero. */
   1.834 +
   1.835 +int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname)
   1.836 +{     struct csa _csa, *csa = &_csa;
   1.837 +      glp_vertex *v;
   1.838 +      int i, j, k, nv, ne, ret = 0;
   1.839 +      double w;
   1.840 +      char *flag = NULL;
   1.841 +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
   1.842 +         xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n",
   1.843 +            v_wgt);
   1.844 +      glp_erase_graph(G, G->v_size, G->a_size);
   1.845 +      if (setjmp(csa->jump))
   1.846 +      {  ret = 1;
   1.847 +         goto done;
   1.848 +      }
   1.849 +      csa->fname = fname;
   1.850 +      csa->fp = NULL;
   1.851 +      csa->count = 0;
   1.852 +      csa->c = '\n';
   1.853 +      csa->field[0] = '\0';
   1.854 +      csa->empty = csa->nonint = 0;
   1.855 +      xprintf("Reading graph from `%s'...\n", fname);
   1.856 +      csa->fp = xfopen(fname, "r");
   1.857 +      if (csa->fp == NULL)
   1.858 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   1.859 +         longjmp(csa->jump, 1);
   1.860 +      }
   1.861 +      /* read problem line */
   1.862 +      read_designator(csa);
   1.863 +      if (strcmp(csa->field, "p") != 0)
   1.864 +         error(csa, "problem line missing or invalid");
   1.865 +      read_field(csa);
   1.866 +      if (strcmp(csa->field, "edge") != 0)
   1.867 +         error(csa, "wrong problem designator; `edge' expected");
   1.868 +      read_field(csa);
   1.869 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
   1.870 +         error(csa, "number of vertices missing or invalid");
   1.871 +      read_field(csa);
   1.872 +      if (!(str2int(csa->field, &ne) == 0 && ne >= 0))
   1.873 +         error(csa, "number of edges missing or invalid");
   1.874 +      xprintf("Graph has %d vert%s and %d edge%s\n",
   1.875 +         nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s");
   1.876 +      if (nv > 0) glp_add_vertices(G, nv);
   1.877 +      end_of_line(csa);
   1.878 +      /* read node descriptor lines */
   1.879 +      flag = xcalloc(1+nv, sizeof(char));
   1.880 +      memset(&flag[1], 0, nv * sizeof(char));
   1.881 +      if (v_wgt >= 0)
   1.882 +      {  w = 1.0;
   1.883 +         for (i = 1; i <= nv; i++)
   1.884 +         {  v = G->v[i];
   1.885 +            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
   1.886 +         }
   1.887 +      }
   1.888 +      for (;;)
   1.889 +      {  read_designator(csa);
   1.890 +         if (strcmp(csa->field, "n") != 0) break;
   1.891 +         read_field(csa);
   1.892 +         if (str2int(csa->field, &i) != 0)
   1.893 +            error(csa, "vertex number missing or invalid");
   1.894 +         if (!(1 <= i && i <= nv))
   1.895 +            error(csa, "vertex number %d out of range", i);
   1.896 +         if (flag[i])
   1.897 +            error(csa, "duplicate descriptor of vertex %d", i);
   1.898 +         read_field(csa);
   1.899 +         if (str2num(csa->field, &w) != 0)
   1.900 +            error(csa, "vertex weight missing or invalid");
   1.901 +         check_int(csa, w);
   1.902 +         if (v_wgt >= 0)
   1.903 +         {  v = G->v[i];
   1.904 +            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
   1.905 +         }
   1.906 +         flag[i] = 1;
   1.907 +         end_of_line(csa);
   1.908 +      }
   1.909 +      xfree(flag), flag = NULL;
   1.910 +      /* read edge descriptor lines */
   1.911 +      for (k = 1; k <= ne; k++)
   1.912 +      {  if (k > 1) read_designator(csa);
   1.913 +         if (strcmp(csa->field, "e") != 0)
   1.914 +            error(csa, "wrong line designator; `e' expected");
   1.915 +         read_field(csa);
   1.916 +         if (str2int(csa->field, &i) != 0)
   1.917 +            error(csa, "first vertex number missing or invalid");
   1.918 +         if (!(1 <= i && i <= nv))
   1.919 +            error(csa, "first vertex number %d out of range", i);
   1.920 +         read_field(csa);
   1.921 +         if (str2int(csa->field, &j) != 0)
   1.922 +            error(csa, "second vertex number missing or invalid");
   1.923 +         if (!(1 <= j && j <= nv))
   1.924 +            error(csa, "second vertex number %d out of range", j);
   1.925 +         glp_add_arc(G, i, j);
   1.926 +         end_of_line(csa);
   1.927 +      }
   1.928 +      xprintf("%d lines were read\n", csa->count);
   1.929 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
   1.930 +      if (csa->fp != NULL) xfclose(csa->fp);
   1.931 +      if (flag != NULL) xfree(flag);
   1.932 +      return ret;
   1.933 +}
   1.934 +
   1.935 +/***********************************************************************
   1.936 +*  NAME
   1.937 +*
   1.938 +*  glp_write_ccdata - write graph in DIMACS clique/coloring format
   1.939 +*
   1.940 +*  SYNOPSIS
   1.941 +*
   1.942 +*  int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
   1.943 +*
   1.944 +*  DESCRIPTION
   1.945 +*
   1.946 +*  The routine glp_write_ccdata writes the specified graph in DIMACS
   1.947 +*  clique/coloring format to a text file.
   1.948 +*
   1.949 +*  RETURNS
   1.950 +*
   1.951 +*  If the operation was successful, the routine returns zero. Otherwise
   1.952 +*  it prints an error message and returns non-zero. */
   1.953 +
   1.954 +int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname)
   1.955 +{     XFILE *fp;
   1.956 +      glp_vertex *v;
   1.957 +      glp_arc *e;
   1.958 +      int i, count = 0, ret;
   1.959 +      double w;
   1.960 +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
   1.961 +         xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n",
   1.962 +            v_wgt);
   1.963 +      xprintf("Writing graph to `%s'\n", fname);
   1.964 +      fp = xfopen(fname, "w");
   1.965 +      if (fp == NULL)
   1.966 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
   1.967 +         ret = 1;
   1.968 +         goto done;
   1.969 +      }
   1.970 +      xfprintf(fp, "c %s\n",
   1.971 +         G->name == NULL ? "unknown" : G->name), count++;
   1.972 +      xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++;
   1.973 +      if (v_wgt >= 0)
   1.974 +      {  for (i = 1; i <= G->nv; i++)
   1.975 +         {  v = G->v[i];
   1.976 +            memcpy(&w, (char *)v->data + v_wgt, sizeof(double));
   1.977 +            if (w != 1.0)
   1.978 +               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++;
   1.979 +         }
   1.980 +      }
   1.981 +      for (i = 1; i <= G->nv; i++)
   1.982 +      {  v = G->v[i];
   1.983 +         for (e = v->out; e != NULL; e = e->t_next)
   1.984 +            xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++;
   1.985 +      }
   1.986 +      xfprintf(fp, "c eof\n"), count++;
   1.987 +      xfflush(fp);
   1.988 +      if (xferror(fp))
   1.989 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
   1.990 +         ret = 1;
   1.991 +         goto done;
   1.992 +      }
   1.993 +      xprintf("%d lines were written\n", count);
   1.994 +      ret = 0;
   1.995 +done: if (fp != NULL) xfclose(fp);
   1.996 +      return ret;
   1.997 +}
   1.998 +
   1.999 +/***********************************************************************
  1.1000 +*  NAME
  1.1001 +*
  1.1002 +*  glp_read_prob - read problem data in GLPK format
  1.1003 +*
  1.1004 +*  SYNOPSIS
  1.1005 +*
  1.1006 +*  int glp_read_prob(glp_prob *P, int flags, const char *fname);
  1.1007 +*
  1.1008 +*  The routine glp_read_prob reads problem data in GLPK LP/MIP format
  1.1009 +*  from a text file.
  1.1010 +*
  1.1011 +*  RETURNS
  1.1012 +*
  1.1013 +*  If the operation was successful, the routine returns zero. Otherwise
  1.1014 +*  it prints an error message and returns non-zero. */
  1.1015 +
  1.1016 +int glp_read_prob(glp_prob *P, int flags, const char *fname)
  1.1017 +{     struct csa _csa, *csa = &_csa;
  1.1018 +      int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL,
  1.1019 +         *ia = NULL, *ja = NULL;
  1.1020 +      double lb, ub, temp, *ar = NULL;
  1.1021 +      char *rf = NULL, *cf = NULL;
  1.1022 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
  1.1023 +         xerror("glp_read_prob: P = %p; invalid problem object\n",
  1.1024 +            P);
  1.1025 +      if (flags != 0)
  1.1026 +         xerror("glp_read_prob: flags = %d; invalid parameter\n",
  1.1027 +            flags);
  1.1028 +      if (fname == NULL)
  1.1029 +         xerror("glp_read_prob: fname = %d; invalid parameter\n",
  1.1030 +            fname);
  1.1031 +      glp_erase_prob(P);
  1.1032 +      if (setjmp(csa->jump))
  1.1033 +      {  ret = 1;
  1.1034 +         goto done;
  1.1035 +      }
  1.1036 +      csa->fname = fname;
  1.1037 +      csa->fp = NULL;
  1.1038 +      csa->count = 0;
  1.1039 +      csa->c = '\n';
  1.1040 +      csa->field[0] = '\0';
  1.1041 +      csa->empty = csa->nonint = 0;
  1.1042 +      xprintf("Reading problem data from `%s'...\n", fname);
  1.1043 +      csa->fp = xfopen(fname, "r");
  1.1044 +      if (csa->fp == NULL)
  1.1045 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
  1.1046 +         longjmp(csa->jump, 1);
  1.1047 +      }
  1.1048 +      /* read problem line */
  1.1049 +      read_designator(csa);
  1.1050 +      if (strcmp(csa->field, "p") != 0)
  1.1051 +         error(csa, "problem line missing or invalid");
  1.1052 +      read_field(csa);
  1.1053 +      if (strcmp(csa->field, "lp") == 0)
  1.1054 +         mip = 0;
  1.1055 +      else if (strcmp(csa->field, "mip") == 0)
  1.1056 +         mip = 1;
  1.1057 +      else
  1.1058 +         error(csa, "wrong problem designator; `lp' or `mip' expected\n"
  1.1059 +            );
  1.1060 +      read_field(csa);
  1.1061 +      if (strcmp(csa->field, "min") == 0)
  1.1062 +         glp_set_obj_dir(P, GLP_MIN);
  1.1063 +      else if (strcmp(csa->field, "max") == 0)
  1.1064 +         glp_set_obj_dir(P, GLP_MAX);
  1.1065 +      else
  1.1066 +         error(csa, "objective sense missing or invalid");
  1.1067 +      read_field(csa);
  1.1068 +      if (!(str2int(csa->field, &m) == 0 && m >= 0))
  1.1069 +         error(csa, "number of rows missing or invalid");
  1.1070 +      read_field(csa);
  1.1071 +      if (!(str2int(csa->field, &n) == 0 && n >= 0))
  1.1072 +         error(csa, "number of columns missing or invalid");
  1.1073 +      read_field(csa);
  1.1074 +      if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0))
  1.1075 +         error(csa, "number of constraint coefficients missing or inval"
  1.1076 +            "id");
  1.1077 +      if (m > 0)
  1.1078 +      {  glp_add_rows(P, m);
  1.1079 +         for (i = 1; i <= m; i++)
  1.1080 +            glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0);
  1.1081 +      }
  1.1082 +      if (n > 0)
  1.1083 +      {  glp_add_cols(P, n);
  1.1084 +         for (j = 1; j <= n; j++)
  1.1085 +         {  if (!mip)
  1.1086 +               glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0);
  1.1087 +            else
  1.1088 +               glp_set_col_kind(P, j, GLP_BV);
  1.1089 +         }
  1.1090 +      }
  1.1091 +      end_of_line(csa);
  1.1092 +      /* allocate working arrays */
  1.1093 +      rf = xcalloc(1+m, sizeof(char));
  1.1094 +      memset(rf, 0, 1+m);
  1.1095 +      cf = xcalloc(1+n, sizeof(char));
  1.1096 +      memset(cf, 0, 1+n);
  1.1097 +      ln = xcalloc(1+nnz, sizeof(int));
  1.1098 +      ia = xcalloc(1+nnz, sizeof(int));
  1.1099 +      ja = xcalloc(1+nnz, sizeof(int));
  1.1100 +      ar = xcalloc(1+nnz, sizeof(double));
  1.1101 +      /* read descriptor lines */
  1.1102 +      ne = 0;
  1.1103 +      for (;;)
  1.1104 +      {  read_designator(csa);
  1.1105 +         if (strcmp(csa->field, "i") == 0)
  1.1106 +         {  /* row descriptor */
  1.1107 +            read_field(csa);
  1.1108 +            if (str2int(csa->field, &i) != 0)
  1.1109 +               error(csa, "row number missing or invalid");
  1.1110 +            if (!(1 <= i && i <= m))
  1.1111 +               error(csa, "row number out of range");
  1.1112 +            read_field(csa);
  1.1113 +            if (strcmp(csa->field, "f") == 0)
  1.1114 +               type = GLP_FR;
  1.1115 +            else if (strcmp(csa->field, "l") == 0)
  1.1116 +               type = GLP_LO;
  1.1117 +            else if (strcmp(csa->field, "u") == 0)
  1.1118 +               type = GLP_UP;
  1.1119 +            else if (strcmp(csa->field, "d") == 0)
  1.1120 +               type = GLP_DB;
  1.1121 +            else if (strcmp(csa->field, "s") == 0)
  1.1122 +               type = GLP_FX;
  1.1123 +            else
  1.1124 +               error(csa, "row type missing or invalid");
  1.1125 +            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
  1.1126 +            {  read_field(csa);
  1.1127 +               if (str2num(csa->field, &lb) != 0)
  1.1128 +                  error(csa, "row lower bound/fixed value missing or in"
  1.1129 +                     "valid");
  1.1130 +            }
  1.1131 +            else
  1.1132 +               lb = 0.0;
  1.1133 +            if (type == GLP_UP || type == GLP_DB)
  1.1134 +            {  read_field(csa);
  1.1135 +               if (str2num(csa->field, &ub) != 0)
  1.1136 +                  error(csa, "row upper bound missing or invalid");
  1.1137 +            }
  1.1138 +            else
  1.1139 +               ub = 0.0;
  1.1140 +            if (rf[i] & 0x01)
  1.1141 +               error(csa, "duplicate row descriptor");
  1.1142 +            glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01;
  1.1143 +         }
  1.1144 +         else if (strcmp(csa->field, "j") == 0)
  1.1145 +         {  /* column descriptor */
  1.1146 +            read_field(csa);
  1.1147 +            if (str2int(csa->field, &j) != 0)
  1.1148 +               error(csa, "column number missing or invalid");
  1.1149 +            if (!(1 <= j && j <= n))
  1.1150 +               error(csa, "column number out of range");
  1.1151 +            if (!mip)
  1.1152 +               kind = GLP_CV;
  1.1153 +            else
  1.1154 +            {  read_field(csa);
  1.1155 +               if (strcmp(csa->field, "c") == 0)
  1.1156 +                  kind = GLP_CV;
  1.1157 +               else if (strcmp(csa->field, "i") == 0)
  1.1158 +                  kind = GLP_IV;
  1.1159 +               else if (strcmp(csa->field, "b") == 0)
  1.1160 +               {  kind = GLP_IV;
  1.1161 +                  type = GLP_DB, lb = 0.0, ub = 1.0;
  1.1162 +                  goto skip;
  1.1163 +               }
  1.1164 +               else
  1.1165 +                  error(csa, "column kind missing or invalid");
  1.1166 +            }
  1.1167 +            read_field(csa);
  1.1168 +            if (strcmp(csa->field, "f") == 0)
  1.1169 +               type = GLP_FR;
  1.1170 +            else if (strcmp(csa->field, "l") == 0)
  1.1171 +               type = GLP_LO;
  1.1172 +            else if (strcmp(csa->field, "u") == 0)
  1.1173 +               type = GLP_UP;
  1.1174 +            else if (strcmp(csa->field, "d") == 0)
  1.1175 +               type = GLP_DB;
  1.1176 +            else if (strcmp(csa->field, "s") == 0)
  1.1177 +               type = GLP_FX;
  1.1178 +            else
  1.1179 +               error(csa, "column type missing or invalid");
  1.1180 +            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
  1.1181 +            {  read_field(csa);
  1.1182 +               if (str2num(csa->field, &lb) != 0)
  1.1183 +                  error(csa, "column lower bound/fixed value missing or"
  1.1184 +                     " invalid");
  1.1185 +            }
  1.1186 +            else
  1.1187 +               lb = 0.0;
  1.1188 +            if (type == GLP_UP || type == GLP_DB)
  1.1189 +            {  read_field(csa);
  1.1190 +               if (str2num(csa->field, &ub) != 0)
  1.1191 +                  error(csa, "column upper bound missing or invalid");
  1.1192 +            }
  1.1193 +            else
  1.1194 +               ub = 0.0;
  1.1195 +skip:       if (cf[j] & 0x01)
  1.1196 +               error(csa, "duplicate column descriptor");
  1.1197 +            glp_set_col_kind(P, j, kind);
  1.1198 +            glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01;
  1.1199 +         }
  1.1200 +         else if (strcmp(csa->field, "a") == 0)
  1.1201 +         {  /* coefficient descriptor */
  1.1202 +            read_field(csa);
  1.1203 +            if (str2int(csa->field, &i) != 0)
  1.1204 +               error(csa, "row number missing or invalid");
  1.1205 +            if (!(0 <= i && i <= m))
  1.1206 +               error(csa, "row number out of range");
  1.1207 +            read_field(csa);
  1.1208 +            if (str2int(csa->field, &j) != 0)
  1.1209 +               error(csa, "column number missing or invalid");
  1.1210 +            if (!((i == 0 ? 0 : 1) <= j && j <= n))
  1.1211 +               error(csa, "column number out of range");
  1.1212 +            read_field(csa);
  1.1213 +            if (i == 0)
  1.1214 +            {  if (str2num(csa->field, &temp) != 0)
  1.1215 +                  error(csa, "objective %s missing or invalid",
  1.1216 +                     j == 0 ? "constant term" : "coefficient");
  1.1217 +               if (cf[j] & 0x10)
  1.1218 +                  error(csa, "duplicate objective %s",
  1.1219 +                     j == 0 ? "constant term" : "coefficient");
  1.1220 +               glp_set_obj_coef(P, j, temp), cf[j] |= 0x10;
  1.1221 +            }
  1.1222 +            else
  1.1223 +            {  if (str2num(csa->field, &temp) != 0)
  1.1224 +                  error(csa, "constraint coefficient missing or invalid"
  1.1225 +                     );
  1.1226 +               if (ne == nnz)
  1.1227 +                  error(csa, "too many constraint coefficient descripto"
  1.1228 +                     "rs");
  1.1229 +               ln[++ne] = csa->count;
  1.1230 +               ia[ne] = i, ja[ne] = j, ar[ne] = temp;
  1.1231 +            }
  1.1232 +         }
  1.1233 +         else if (strcmp(csa->field, "n") == 0)
  1.1234 +         {  /* symbolic name descriptor */
  1.1235 +            read_field(csa);
  1.1236 +            if (strcmp(csa->field, "p") == 0)
  1.1237 +            {  /* problem name */
  1.1238 +               read_field(csa);
  1.1239 +               if (P->name != NULL)
  1.1240 +                  error(csa, "duplicate problem name");
  1.1241 +               glp_set_prob_name(P, csa->field);
  1.1242 +            }
  1.1243 +            else if (strcmp(csa->field, "z") == 0)
  1.1244 +            {  /* objective name */
  1.1245 +               read_field(csa);
  1.1246 +               if (P->obj != NULL)
  1.1247 +                  error(csa, "duplicate objective name");
  1.1248 +               glp_set_obj_name(P, csa->field);
  1.1249 +            }
  1.1250 +            else if (strcmp(csa->field, "i") == 0)
  1.1251 +            {  /* row name */
  1.1252 +               read_field(csa);
  1.1253 +               if (str2int(csa->field, &i) != 0)
  1.1254 +                  error(csa, "row number missing or invalid");
  1.1255 +               if (!(1 <= i && i <= m))
  1.1256 +                  error(csa, "row number out of range");
  1.1257 +               read_field(csa);
  1.1258 +               if (P->row[i]->name != NULL)
  1.1259 +                  error(csa, "duplicate row name");
  1.1260 +               glp_set_row_name(P, i, csa->field);
  1.1261 +            }
  1.1262 +            else if (strcmp(csa->field, "j") == 0)
  1.1263 +            {  /* column name */
  1.1264 +               read_field(csa);
  1.1265 +               if (str2int(csa->field, &j) != 0)
  1.1266 +                  error(csa, "column number missing or invalid");
  1.1267 +               if (!(1 <= j && j <= n))
  1.1268 +                  error(csa, "column number out of range");
  1.1269 +               read_field(csa);
  1.1270 +               if (P->col[j]->name != NULL)
  1.1271 +                  error(csa, "duplicate column name");
  1.1272 +               glp_set_col_name(P, j, csa->field);
  1.1273 +            }
  1.1274 +            else
  1.1275 +               error(csa, "object designator missing or invalid");
  1.1276 +         }
  1.1277 +         else if (strcmp(csa->field, "e") == 0)
  1.1278 +            break;
  1.1279 +         else
  1.1280 +            error(csa, "line designator missing or invalid");
  1.1281 +         end_of_line(csa);
  1.1282 +      }
  1.1283 +      if (ne < nnz)
  1.1284 +         error(csa, "too few constraint coefficient descriptors");
  1.1285 +      xassert(ne == nnz);
  1.1286 +      k = glp_check_dup(m, n, ne, ia, ja);
  1.1287 +      xassert(0 <= k && k <= nnz);
  1.1288 +      if (k > 0)
  1.1289 +      {  csa->count = ln[k];
  1.1290 +         error(csa, "duplicate constraint coefficient");
  1.1291 +      }
  1.1292 +      glp_load_matrix(P, ne, ia, ja, ar);
  1.1293 +      /* print some statistics */
  1.1294 +      if (P->name != NULL)
  1.1295 +         xprintf("Problem: %s\n", P->name);
  1.1296 +      if (P->obj != NULL)
  1.1297 +         xprintf("Objective: %s\n", P->obj);
  1.1298 +      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
  1.1299 +         m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ?
  1.1300 +         "" : "s");
  1.1301 +      if (glp_get_num_int(P) > 0)
  1.1302 +      {  int ni = glp_get_num_int(P);
  1.1303 +         int nb = glp_get_num_bin(P);
  1.1304 +         if (ni == 1)
  1.1305 +         {  if (nb == 0)
  1.1306 +               xprintf("One variable is integer\n");
  1.1307 +            else
  1.1308 +               xprintf("One variable is binary\n");
  1.1309 +         }
  1.1310 +         else
  1.1311 +         {  xprintf("%d integer variables, ", ni);
  1.1312 +            if (nb == 0)
  1.1313 +               xprintf("none");
  1.1314 +            else if (nb == 1)
  1.1315 +               xprintf("one");
  1.1316 +            else if (nb == ni)
  1.1317 +               xprintf("all");
  1.1318 +            else
  1.1319 +               xprintf("%d", nb);
  1.1320 +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
  1.1321 +         }
  1.1322 +      }
  1.1323 +      xprintf("%d lines were read\n", csa->count);
  1.1324 +      /* problem data has been successfully read */
  1.1325 +      glp_sort_matrix(P);
  1.1326 +      ret = 0;
  1.1327 +done: if (csa->fp != NULL) xfclose(csa->fp);
  1.1328 +      if (rf != NULL) xfree(rf);
  1.1329 +      if (cf != NULL) xfree(cf);
  1.1330 +      if (ln != NULL) xfree(ln);
  1.1331 +      if (ia != NULL) xfree(ia);
  1.1332 +      if (ja != NULL) xfree(ja);
  1.1333 +      if (ar != NULL) xfree(ar);
  1.1334 +      if (ret) glp_erase_prob(P);
  1.1335 +      return ret;
  1.1336 +}
  1.1337 +
  1.1338 +/***********************************************************************
  1.1339 +*  NAME
  1.1340 +*
  1.1341 +*  glp_write_prob - write problem data in GLPK format
  1.1342 +*
  1.1343 +*  SYNOPSIS
  1.1344 +*
  1.1345 +*  int glp_write_prob(glp_prob *P, int flags, const char *fname);
  1.1346 +*
  1.1347 +*  The routine glp_write_prob writes problem data in GLPK LP/MIP format
  1.1348 +*  to a text file.
  1.1349 +*
  1.1350 +*  RETURNS
  1.1351 +*
  1.1352 +*  If the operation was successful, the routine returns zero. Otherwise
  1.1353 +*  it prints an error message and returns non-zero. */
  1.1354 +
  1.1355 +int glp_write_prob(glp_prob *P, int flags, const char *fname)
  1.1356 +{     XFILE *fp;
  1.1357 +      GLPROW *row;
  1.1358 +      GLPCOL *col;
  1.1359 +      GLPAIJ *aij;
  1.1360 +      int mip, i, j, count, ret;
  1.1361 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
  1.1362 +         xerror("glp_write_prob: P = %p; invalid problem object\n",
  1.1363 +            P);
  1.1364 +      if (flags != 0)
  1.1365 +         xerror("glp_write_prob: flags = %d; invalid parameter\n",
  1.1366 +            flags);
  1.1367 +      if (fname == NULL)
  1.1368 +         xerror("glp_write_prob: fname = %d; invalid parameter\n",
  1.1369 +            fname);
  1.1370 +      xprintf("Writing problem data to `%s'...\n", fname);
  1.1371 +      fp = xfopen(fname, "w"), count = 0;
  1.1372 +      if (fp == NULL)
  1.1373 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
  1.1374 +         ret = 1;
  1.1375 +         goto done;
  1.1376 +      }
  1.1377 +      /* write problem line */
  1.1378 +      mip = (glp_get_num_int(P) > 0);
  1.1379 +      xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip",
  1.1380 +         P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???",
  1.1381 +         P->m, P->n, P->nnz), count++;
  1.1382 +      if (P->name != NULL)
  1.1383 +         xfprintf(fp, "n p %s\n", P->name), count++;
  1.1384 +      if (P->obj != NULL)
  1.1385 +         xfprintf(fp, "n z %s\n", P->obj), count++;
  1.1386 +      /* write row descriptors */
  1.1387 +      for (i = 1; i <= P->m; i++)
  1.1388 +      {  row = P->row[i];
  1.1389 +         if (row->type == GLP_FX && row->lb == 0.0)
  1.1390 +            goto skip1;
  1.1391 +         xfprintf(fp, "i %d ", i), count++;
  1.1392 +         if (row->type == GLP_FR)
  1.1393 +            xfprintf(fp, "f\n");
  1.1394 +         else if (row->type == GLP_LO)
  1.1395 +            xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb);
  1.1396 +         else if (row->type == GLP_UP)
  1.1397 +            xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub);
  1.1398 +         else if (row->type == GLP_DB)
  1.1399 +            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG,
  1.1400 +                  row->ub);
  1.1401 +         else if (row->type == GLP_FX)
  1.1402 +            xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb);
  1.1403 +         else
  1.1404 +            xassert(row != row);
  1.1405 +skip1:   if (row->name != NULL)
  1.1406 +            xfprintf(fp, "n i %d %s\n", i, row->name), count++;
  1.1407 +      }
  1.1408 +      /* write column descriptors */
  1.1409 +      for (j = 1; j <= P->n; j++)
  1.1410 +      {  col = P->col[j];
  1.1411 +         if (!mip && col->type == GLP_LO && col->lb == 0.0)
  1.1412 +            goto skip2;
  1.1413 +         if (mip && col->kind == GLP_IV && col->type == GLP_DB &&
  1.1414 +             col->lb == 0.0 && col->ub == 1.0)
  1.1415 +            goto skip2;
  1.1416 +         xfprintf(fp, "j %d ", j), count++;
  1.1417 +         if (mip)
  1.1418 +         {  if (col->kind == GLP_CV)
  1.1419 +               xfprintf(fp, "c ");
  1.1420 +            else if (col->kind == GLP_IV)
  1.1421 +               xfprintf(fp, "i ");
  1.1422 +            else
  1.1423 +               xassert(col != col);
  1.1424 +         }
  1.1425 +         if (col->type == GLP_FR)
  1.1426 +            xfprintf(fp, "f\n");
  1.1427 +         else if (col->type == GLP_LO)
  1.1428 +            xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb);
  1.1429 +         else if (col->type == GLP_UP)
  1.1430 +            xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub);
  1.1431 +         else if (col->type == GLP_DB)
  1.1432 +            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG,
  1.1433 +                  col->ub);
  1.1434 +         else if (col->type == GLP_FX)
  1.1435 +            xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb);
  1.1436 +         else
  1.1437 +            xassert(col != col);
  1.1438 +skip2:   if (col->name != NULL)
  1.1439 +            xfprintf(fp, "n j %d %s\n", j, col->name), count++;
  1.1440 +      }
  1.1441 +      /* write objective coefficient descriptors */
  1.1442 +      if (P->c0 != 0.0)
  1.1443 +         xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++;
  1.1444 +      for (j = 1; j <= P->n; j++)
  1.1445 +      {  col = P->col[j];
  1.1446 +         if (col->coef != 0.0)
  1.1447 +            xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef),
  1.1448 +               count++;
  1.1449 +      }
  1.1450 +      /* write constraint coefficient descriptors */
  1.1451 +      for (i = 1; i <= P->m; i++)
  1.1452 +      {  row = P->row[i];
  1.1453 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  1.1454 +            xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG,
  1.1455 +               aij->val), count++;
  1.1456 +      }
  1.1457 +      /* write end line */
  1.1458 +      xfprintf(fp, "e o f\n"), count++;
  1.1459 +      xfflush(fp);
  1.1460 +      if (xferror(fp))
  1.1461 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
  1.1462 +         ret = 1;
  1.1463 +         goto done;
  1.1464 +      }
  1.1465 +      xprintf("%d lines were written\n", count);
  1.1466 +      ret = 0;
  1.1467 +done: if (fp != NULL) xfclose(fp);
  1.1468 +      return ret;
  1.1469 +}
  1.1470 +
  1.1471 +/* eof */