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 */