src/glpdmx.c
changeset 2 4c8956a7bdf4
equal deleted inserted replaced
-1:000000000000 0:437284ba184e
       
     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 */