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