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