lemon-project-template-glpk

view deps/glpk/src/glpapi11.c @ 9:33de93886c88

Import GLPK 4.47
author Alpar Juttner <alpar@cs.elte.hu>
date Sun, 06 Nov 2011 20:59:10 +0100
parents
children
line source
1 /* glpapi11.c (utility routines) */
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, 2011 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 ***********************************************************************/
25 #include "glpapi.h"
27 int glp_print_sol(glp_prob *P, const char *fname)
28 { /* write basic solution in printable format */
29 XFILE *fp;
30 GLPROW *row;
31 GLPCOL *col;
32 int i, j, t, ae_ind, re_ind, ret;
33 double ae_max, re_max;
34 xprintf("Writing basic solution to `%s'...\n", fname);
35 fp = xfopen(fname, "w");
36 if (fp == NULL)
37 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
38 ret = 1;
39 goto done;
40 }
41 xfprintf(fp, "%-12s%s\n", "Problem:",
42 P->name == NULL ? "" : P->name);
43 xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
44 xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
45 xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
46 t = glp_get_status(P);
47 xfprintf(fp, "%-12s%s\n", "Status:",
48 t == GLP_OPT ? "OPTIMAL" :
49 t == GLP_FEAS ? "FEASIBLE" :
50 t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
51 t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" :
52 t == GLP_UNBND ? "UNBOUNDED" :
53 t == GLP_UNDEF ? "UNDEFINED" : "???");
54 xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
55 P->obj == NULL ? "" : P->obj,
56 P->obj == NULL ? "" : " = ", P->obj_val,
57 P->dir == GLP_MIN ? "MINimum" :
58 P->dir == GLP_MAX ? "MAXimum" : "???");
59 xfprintf(fp, "\n");
60 xfprintf(fp, " No. Row name St Activity Lower bound "
61 " Upper bound Marginal\n");
62 xfprintf(fp, "------ ------------ -- ------------- ------------- "
63 "------------- -------------\n");
64 for (i = 1; i <= P->m; i++)
65 { row = P->row[i];
66 xfprintf(fp, "%6d ", i);
67 if (row->name == NULL || strlen(row->name) <= 12)
68 xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
69 else
70 xfprintf(fp, "%s\n%20s", row->name, "");
71 xfprintf(fp, "%s ",
72 row->stat == GLP_BS ? "B " :
73 row->stat == GLP_NL ? "NL" :
74 row->stat == GLP_NU ? "NU" :
75 row->stat == GLP_NF ? "NF" :
76 row->stat == GLP_NS ? "NS" : "??");
77 xfprintf(fp, "%13.6g ",
78 fabs(row->prim) <= 1e-9 ? 0.0 : row->prim);
79 if (row->type == GLP_LO || row->type == GLP_DB ||
80 row->type == GLP_FX)
81 xfprintf(fp, "%13.6g ", row->lb);
82 else
83 xfprintf(fp, "%13s ", "");
84 if (row->type == GLP_UP || row->type == GLP_DB)
85 xfprintf(fp, "%13.6g ", row->ub);
86 else
87 xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
88 if (row->stat != GLP_BS)
89 { if (fabs(row->dual) <= 1e-9)
90 xfprintf(fp, "%13s", "< eps");
91 else
92 xfprintf(fp, "%13.6g ", row->dual);
93 }
94 xfprintf(fp, "\n");
95 }
96 xfprintf(fp, "\n");
97 xfprintf(fp, " No. Column name St Activity Lower bound "
98 " Upper bound Marginal\n");
99 xfprintf(fp, "------ ------------ -- ------------- ------------- "
100 "------------- -------------\n");
101 for (j = 1; j <= P->n; j++)
102 { col = P->col[j];
103 xfprintf(fp, "%6d ", j);
104 if (col->name == NULL || strlen(col->name) <= 12)
105 xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
106 else
107 xfprintf(fp, "%s\n%20s", col->name, "");
108 xfprintf(fp, "%s ",
109 col->stat == GLP_BS ? "B " :
110 col->stat == GLP_NL ? "NL" :
111 col->stat == GLP_NU ? "NU" :
112 col->stat == GLP_NF ? "NF" :
113 col->stat == GLP_NS ? "NS" : "??");
114 xfprintf(fp, "%13.6g ",
115 fabs(col->prim) <= 1e-9 ? 0.0 : col->prim);
116 if (col->type == GLP_LO || col->type == GLP_DB ||
117 col->type == GLP_FX)
118 xfprintf(fp, "%13.6g ", col->lb);
119 else
120 xfprintf(fp, "%13s ", "");
121 if (col->type == GLP_UP || col->type == GLP_DB)
122 xfprintf(fp, "%13.6g ", col->ub);
123 else
124 xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
125 if (col->stat != GLP_BS)
126 { if (fabs(col->dual) <= 1e-9)
127 xfprintf(fp, "%13s", "< eps");
128 else
129 xfprintf(fp, "%13.6g ", col->dual);
130 }
131 xfprintf(fp, "\n");
132 }
133 xfprintf(fp, "\n");
134 xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
135 xfprintf(fp, "\n");
136 _glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
137 &re_ind);
138 xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
139 ae_max, ae_ind);
140 xfprintf(fp, " max.rel.err = %.2e on row %d\n",
141 re_max, re_ind);
142 xfprintf(fp, "%8s%s\n", "",
143 re_max <= 1e-9 ? "High quality" :
144 re_max <= 1e-6 ? "Medium quality" :
145 re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
146 xfprintf(fp, "\n");
147 _glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
148 &re_ind);
149 xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
150 ae_max, ae_ind <= P->m ? "row" : "column",
151 ae_ind <= P->m ? ae_ind : ae_ind - P->m);
152 xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
153 re_max, re_ind <= P->m ? "row" : "column",
154 re_ind <= P->m ? re_ind : re_ind - P->m);
155 xfprintf(fp, "%8s%s\n", "",
156 re_max <= 1e-9 ? "High quality" :
157 re_max <= 1e-6 ? "Medium quality" :
158 re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
159 "E");
160 xfprintf(fp, "\n");
161 _glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
162 &re_ind);
163 xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
164 ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
165 xfprintf(fp, " max.rel.err = %.2e on column %d\n",
166 re_max, re_ind == 0 ? 0 : re_ind - P->m);
167 xfprintf(fp, "%8s%s\n", "",
168 re_max <= 1e-9 ? "High quality" :
169 re_max <= 1e-6 ? "Medium quality" :
170 re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
171 xfprintf(fp, "\n");
172 _glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
173 &re_ind);
174 xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
175 ae_max, ae_ind <= P->m ? "row" : "column",
176 ae_ind <= P->m ? ae_ind : ae_ind - P->m);
177 xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
178 re_max, re_ind <= P->m ? "row" : "column",
179 re_ind <= P->m ? re_ind : re_ind - P->m);
180 xfprintf(fp, "%8s%s\n", "",
181 re_max <= 1e-9 ? "High quality" :
182 re_max <= 1e-6 ? "Medium quality" :
183 re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
184 ;
185 xfprintf(fp, "\n");
186 xfprintf(fp, "End of output\n");
187 xfflush(fp);
188 if (xferror(fp))
189 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
190 ret = 1;
191 goto done;
192 }
193 ret = 0;
194 done: if (fp != NULL) xfclose(fp);
195 return ret;
196 }
198 /***********************************************************************
199 * NAME
200 *
201 * glp_read_sol - read basic solution from text file
202 *
203 * SYNOPSIS
204 *
205 * int glp_read_sol(glp_prob *lp, const char *fname);
206 *
207 * DESCRIPTION
208 *
209 * The routine glp_read_sol reads basic solution from a text file whose
210 * name is specified by the parameter fname into the problem object.
211 *
212 * For the file format see description of the routine glp_write_sol.
213 *
214 * RETURNS
215 *
216 * On success the routine returns zero, otherwise non-zero. */
218 int glp_read_sol(glp_prob *lp, const char *fname)
219 { glp_data *data;
220 jmp_buf jump;
221 int i, j, k, ret = 0;
222 xprintf("Reading basic solution from `%s'...\n", fname);
223 data = glp_sdf_open_file(fname);
224 if (data == NULL)
225 { ret = 1;
226 goto done;
227 }
228 if (setjmp(jump))
229 { ret = 1;
230 goto done;
231 }
232 glp_sdf_set_jump(data, jump);
233 /* number of rows, number of columns */
234 k = glp_sdf_read_int(data);
235 if (k != lp->m)
236 glp_sdf_error(data, "wrong number of rows\n");
237 k = glp_sdf_read_int(data);
238 if (k != lp->n)
239 glp_sdf_error(data, "wrong number of columns\n");
240 /* primal status, dual status, objective value */
241 k = glp_sdf_read_int(data);
242 if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
243 k == GLP_NOFEAS))
244 glp_sdf_error(data, "invalid primal status\n");
245 lp->pbs_stat = k;
246 k = glp_sdf_read_int(data);
247 if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
248 k == GLP_NOFEAS))
249 glp_sdf_error(data, "invalid dual status\n");
250 lp->dbs_stat = k;
251 lp->obj_val = glp_sdf_read_num(data);
252 /* rows (auxiliary variables) */
253 for (i = 1; i <= lp->m; i++)
254 { GLPROW *row = lp->row[i];
255 /* status, primal value, dual value */
256 k = glp_sdf_read_int(data);
257 if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
258 k == GLP_NF || k == GLP_NS))
259 glp_sdf_error(data, "invalid row status\n");
260 glp_set_row_stat(lp, i, k);
261 row->prim = glp_sdf_read_num(data);
262 row->dual = glp_sdf_read_num(data);
263 }
264 /* columns (structural variables) */
265 for (j = 1; j <= lp->n; j++)
266 { GLPCOL *col = lp->col[j];
267 /* status, primal value, dual value */
268 k = glp_sdf_read_int(data);
269 if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
270 k == GLP_NF || k == GLP_NS))
271 glp_sdf_error(data, "invalid column status\n");
272 glp_set_col_stat(lp, j, k);
273 col->prim = glp_sdf_read_num(data);
274 col->dual = glp_sdf_read_num(data);
275 }
276 xprintf("%d lines were read\n", glp_sdf_line(data));
277 done: if (ret) lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
278 if (data != NULL) glp_sdf_close_file(data);
279 return ret;
280 }
282 /***********************************************************************
283 * NAME
284 *
285 * glp_write_sol - write basic solution to text file
286 *
287 * SYNOPSIS
288 *
289 * int glp_write_sol(glp_prob *lp, const char *fname);
290 *
291 * DESCRIPTION
292 *
293 * The routine glp_write_sol writes the current basic solution to a
294 * text file whose name is specified by the parameter fname. This file
295 * can be read back with the routine glp_read_sol.
296 *
297 * RETURNS
298 *
299 * On success the routine returns zero, otherwise non-zero.
300 *
301 * FILE FORMAT
302 *
303 * The file created by the routine glp_write_sol is a plain text file,
304 * which contains the following information:
305 *
306 * m n
307 * p_stat d_stat obj_val
308 * r_stat[1] r_prim[1] r_dual[1]
309 * . . .
310 * r_stat[m] r_prim[m] r_dual[m]
311 * c_stat[1] c_prim[1] c_dual[1]
312 * . . .
313 * c_stat[n] c_prim[n] c_dual[n]
314 *
315 * where:
316 * m is the number of rows (auxiliary variables);
317 * n is the number of columns (structural variables);
318 * p_stat is the primal status of the basic solution (GLP_UNDEF = 1,
319 * GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
320 * d_stat is the dual status of the basic solution (GLP_UNDEF = 1,
321 * GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
322 * obj_val is the objective value;
323 * r_stat[i], i = 1,...,m, is the status of i-th row (GLP_BS = 1,
324 * GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
325 * r_prim[i], i = 1,...,m, is the primal value of i-th row;
326 * r_dual[i], i = 1,...,m, is the dual value of i-th row;
327 * c_stat[j], j = 1,...,n, is the status of j-th column (GLP_BS = 1,
328 * GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
329 * c_prim[j], j = 1,...,n, is the primal value of j-th column;
330 * c_dual[j], j = 1,...,n, is the dual value of j-th column. */
332 int glp_write_sol(glp_prob *lp, const char *fname)
333 { XFILE *fp;
334 int i, j, ret = 0;
335 xprintf("Writing basic solution to `%s'...\n", fname);
336 fp = xfopen(fname, "w");
337 if (fp == NULL)
338 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
339 ret = 1;
340 goto done;
341 }
342 /* number of rows, number of columns */
343 xfprintf(fp, "%d %d\n", lp->m, lp->n);
344 /* primal status, dual status, objective value */
345 xfprintf(fp, "%d %d %.*g\n", lp->pbs_stat, lp->dbs_stat, DBL_DIG,
346 lp->obj_val);
347 /* rows (auxiliary variables) */
348 for (i = 1; i <= lp->m; i++)
349 { GLPROW *row = lp->row[i];
350 /* status, primal value, dual value */
351 xfprintf(fp, "%d %.*g %.*g\n", row->stat, DBL_DIG, row->prim,
352 DBL_DIG, row->dual);
353 }
354 /* columns (structural variables) */
355 for (j = 1; j <= lp->n; j++)
356 { GLPCOL *col = lp->col[j];
357 /* status, primal value, dual value */
358 xfprintf(fp, "%d %.*g %.*g\n", col->stat, DBL_DIG, col->prim,
359 DBL_DIG, col->dual);
360 }
361 xfflush(fp);
362 if (xferror(fp))
363 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
364 ret = 1;
365 goto done;
366 }
367 xprintf("%d lines were written\n", 2 + lp->m + lp->n);
368 done: if (fp != NULL) xfclose(fp);
369 return ret;
370 }
372 /**********************************************************************/
374 static char *format(char buf[13+1], double x)
375 { /* format floating-point number in MPS/360-like style */
376 if (x == -DBL_MAX)
377 strcpy(buf, " -Inf");
378 else if (x == +DBL_MAX)
379 strcpy(buf, " +Inf");
380 else if (fabs(x) <= 999999.99998)
381 { sprintf(buf, "%13.5f", x);
382 #if 1
383 if (strcmp(buf, " 0.00000") == 0 ||
384 strcmp(buf, " -0.00000") == 0)
385 strcpy(buf, " . ");
386 else if (memcmp(buf, " 0.", 8) == 0)
387 memcpy(buf, " .", 8);
388 else if (memcmp(buf, " -0.", 8) == 0)
389 memcpy(buf, " -.", 8);
390 #endif
391 }
392 else
393 sprintf(buf, "%13.6g", x);
394 return buf;
395 }
397 int glp_print_ranges(glp_prob *P, int len, const int list[],
398 int flags, const char *fname)
399 { /* print sensitivity analysis report */
400 XFILE *fp = NULL;
401 GLPROW *row;
402 GLPCOL *col;
403 int m, n, pass, k, t, numb, type, stat, var1, var2, count, page,
404 ret;
405 double lb, ub, slack, coef, prim, dual, value1, value2, coef1,
406 coef2, obj1, obj2;
407 const char *name, *limit;
408 char buf[13+1];
409 /* sanity checks */
410 if (P == NULL || P->magic != GLP_PROB_MAGIC)
411 xerror("glp_print_ranges: P = %p; invalid problem object\n",
412 P);
413 m = P->m, n = P->n;
414 if (len < 0)
415 xerror("glp_print_ranges: len = %d; invalid list length\n",
416 len);
417 if (len > 0)
418 { if (list == NULL)
419 xerror("glp_print_ranges: list = %p: invalid parameter\n",
420 list);
421 for (t = 1; t <= len; t++)
422 { k = list[t];
423 if (!(1 <= k && k <= m+n))
424 xerror("glp_print_ranges: list[%d] = %d; row/column numb"
425 "er out of range\n", t, k);
426 }
427 }
428 if (flags != 0)
429 xerror("glp_print_ranges: flags = %d; invalid parameter\n",
430 flags);
431 if (fname == NULL)
432 xerror("glp_print_ranges: fname = %p; invalid parameter\n",
433 fname);
434 if (glp_get_status(P) != GLP_OPT)
435 { xprintf("glp_print_ranges: optimal basic solution required\n");
436 ret = 1;
437 goto done;
438 }
439 if (!glp_bf_exists(P))
440 { xprintf("glp_print_ranges: basis factorization required\n");
441 ret = 2;
442 goto done;
443 }
444 /* start reporting */
445 xprintf("Write sensitivity analysis report to `%s'...\n", fname);
446 fp = xfopen(fname, "w");
447 if (fp == NULL)
448 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
449 ret = 3;
450 goto done;
451 }
452 page = count = 0;
453 for (pass = 1; pass <= 2; pass++)
454 for (t = 1; t <= (len == 0 ? m+n : len); t++)
455 { if (t == 1) count = 0;
456 k = (len == 0 ? t : list[t]);
457 if (pass == 1 && k > m || pass == 2 && k <= m)
458 continue;
459 if (count == 0)
460 { xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa"
461 "ge%4d\n", glp_version(), "", ++page);
462 xfprintf(fp, "\n");
463 xfprintf(fp, "%-12s%s\n", "Problem:",
464 P->name == NULL ? "" : P->name);
465 xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
466 P->obj == NULL ? "" : P->obj,
467 P->obj == NULL ? "" : " = ", P->obj_val,
468 P->dir == GLP_MIN ? "MINimum" :
469 P->dir == GLP_MAX ? "MAXimum" : "???");
470 xfprintf(fp, "\n");
471 xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s "
472 "%s\n", "No.", pass == 1 ? "Row name" : "Column name",
473 "St", "Activity", pass == 1 ? "Slack" : "Obj coef",
474 "Lower bound", "Activity", "Obj coef", "Obj value at",
475 "Limiting");
476 xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s "
477 "%s\n", "", "", "", "", "Marginal", "Upper bound",
478 "range", "range", "break point", "variable");
479 xfprintf(fp, "------ ------------ -- ------------- --------"
480 "----- ------------- ------------- ------------- ------"
481 "------- ------------\n");
482 }
483 if (pass == 1)
484 { numb = k;
485 xassert(1 <= numb && numb <= m);
486 row = P->row[numb];
487 name = row->name;
488 type = row->type;
489 lb = glp_get_row_lb(P, numb);
490 ub = glp_get_row_ub(P, numb);
491 coef = 0.0;
492 stat = row->stat;
493 prim = row->prim;
494 if (type == GLP_FR)
495 slack = - prim;
496 else if (type == GLP_LO)
497 slack = lb - prim;
498 else if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
499 slack = ub - prim;
500 dual = row->dual;
501 }
502 else
503 { numb = k - m;
504 xassert(1 <= numb && numb <= n);
505 col = P->col[numb];
506 name = col->name;
507 lb = glp_get_col_lb(P, numb);
508 ub = glp_get_col_ub(P, numb);
509 coef = col->coef;
510 stat = col->stat;
511 prim = col->prim;
512 slack = 0.0;
513 dual = col->dual;
514 }
515 if (stat != GLP_BS)
516 { glp_analyze_bound(P, k, &value1, &var1, &value2, &var2);
517 if (stat == GLP_NF)
518 coef1 = coef2 = coef;
519 else if (stat == GLP_NS)
520 coef1 = -DBL_MAX, coef2 = +DBL_MAX;
521 else if (stat == GLP_NL && P->dir == GLP_MIN ||
522 stat == GLP_NU && P->dir == GLP_MAX)
523 coef1 = coef - dual, coef2 = +DBL_MAX;
524 else
525 coef1 = -DBL_MAX, coef2 = coef - dual;
526 if (value1 == -DBL_MAX)
527 { if (dual < -1e-9)
528 obj1 = +DBL_MAX;
529 else if (dual > +1e-9)
530 obj1 = -DBL_MAX;
531 else
532 obj1 = P->obj_val;
533 }
534 else
535 obj1 = P->obj_val + dual * (value1 - prim);
536 if (value2 == +DBL_MAX)
537 { if (dual < -1e-9)
538 obj2 = -DBL_MAX;
539 else if (dual > +1e-9)
540 obj2 = +DBL_MAX;
541 else
542 obj2 = P->obj_val;
543 }
544 else
545 obj2 = P->obj_val + dual * (value2 - prim);
546 }
547 else
548 { glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2,
549 &var2, &value2);
550 if (coef1 == -DBL_MAX)
551 { if (prim < -1e-9)
552 obj1 = +DBL_MAX;
553 else if (prim > +1e-9)
554 obj1 = -DBL_MAX;
555 else
556 obj1 = P->obj_val;
557 }
558 else
559 obj1 = P->obj_val + (coef1 - coef) * prim;
560 if (coef2 == +DBL_MAX)
561 { if (prim < -1e-9)
562 obj2 = -DBL_MAX;
563 else if (prim > +1e-9)
564 obj2 = +DBL_MAX;
565 else
566 obj2 = P->obj_val;
567 }
568 else
569 obj2 = P->obj_val + (coef2 - coef) * prim;
570 }
571 /*** first line ***/
572 /* row/column number */
573 xfprintf(fp, "%6d", numb);
574 /* row/column name */
575 xfprintf(fp, " %-12.12s", name == NULL ? "" : name);
576 if (name != NULL && strlen(name) > 12)
577 xfprintf(fp, "%s\n%6s %12s", name+12, "", "");
578 /* row/column status */
579 xfprintf(fp, " %2s",
580 stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" :
581 stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" :
582 stat == GLP_NS ? "NS" : "??");
583 /* row/column activity */
584 xfprintf(fp, " %s", format(buf, prim));
585 /* row slack, column objective coefficient */
586 xfprintf(fp, " %s", format(buf, k <= m ? slack : coef));
587 /* row/column lower bound */
588 xfprintf(fp, " %s", format(buf, lb));
589 /* row/column activity range */
590 xfprintf(fp, " %s", format(buf, value1));
591 /* row/column objective coefficient range */
592 xfprintf(fp, " %s", format(buf, coef1));
593 /* objective value at break point */
594 xfprintf(fp, " %s", format(buf, obj1));
595 /* limiting variable name */
596 if (var1 != 0)
597 { if (var1 <= m)
598 limit = glp_get_row_name(P, var1);
599 else
600 limit = glp_get_col_name(P, var1 - m);
601 if (limit != NULL)
602 xfprintf(fp, " %s", limit);
603 }
604 xfprintf(fp, "\n");
605 /*** second line ***/
606 xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", "");
607 /* row/column reduced cost */
608 xfprintf(fp, " %s", format(buf, dual));
609 /* row/column upper bound */
610 xfprintf(fp, " %s", format(buf, ub));
611 /* row/column activity range */
612 xfprintf(fp, " %s", format(buf, value2));
613 /* row/column objective coefficient range */
614 xfprintf(fp, " %s", format(buf, coef2));
615 /* objective value at break point */
616 xfprintf(fp, " %s", format(buf, obj2));
617 /* limiting variable name */
618 if (var2 != 0)
619 { if (var2 <= m)
620 limit = glp_get_row_name(P, var2);
621 else
622 limit = glp_get_col_name(P, var2 - m);
623 if (limit != NULL)
624 xfprintf(fp, " %s", limit);
625 }
626 xfprintf(fp, "\n");
627 xfprintf(fp, "\n");
628 /* print 10 items per page */
629 count = (count + 1) % 10;
630 }
631 xfprintf(fp, "End of report\n");
632 xfflush(fp);
633 if (xferror(fp))
634 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
635 ret = 4;
636 goto done;
637 }
638 ret = 0;
639 done: if (fp != NULL) xfclose(fp);
640 return ret;
641 }
643 /**********************************************************************/
645 int glp_print_ipt(glp_prob *P, const char *fname)
646 { /* write interior-point solution in printable format */
647 XFILE *fp;
648 GLPROW *row;
649 GLPCOL *col;
650 int i, j, t, ae_ind, re_ind, ret;
651 double ae_max, re_max;
652 xprintf("Writing interior-point solution to `%s'...\n", fname);
653 fp = xfopen(fname, "w");
654 if (fp == NULL)
655 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
656 ret = 1;
657 goto done;
658 }
659 xfprintf(fp, "%-12s%s\n", "Problem:",
660 P->name == NULL ? "" : P->name);
661 xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
662 xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
663 xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
664 t = glp_ipt_status(P);
665 xfprintf(fp, "%-12s%s\n", "Status:",
666 t == GLP_OPT ? "OPTIMAL" :
667 t == GLP_UNDEF ? "UNDEFINED" :
668 t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
669 t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???");
670 xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
671 P->obj == NULL ? "" : P->obj,
672 P->obj == NULL ? "" : " = ", P->ipt_obj,
673 P->dir == GLP_MIN ? "MINimum" :
674 P->dir == GLP_MAX ? "MAXimum" : "???");
675 xfprintf(fp, "\n");
676 xfprintf(fp, " No. Row name Activity Lower bound "
677 " Upper bound Marginal\n");
678 xfprintf(fp, "------ ------------ ------------- ------------- "
679 "------------- -------------\n");
680 for (i = 1; i <= P->m; i++)
681 { row = P->row[i];
682 xfprintf(fp, "%6d ", i);
683 if (row->name == NULL || strlen(row->name) <= 12)
684 xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
685 else
686 xfprintf(fp, "%s\n%20s", row->name, "");
687 xfprintf(fp, "%3s", "");
688 xfprintf(fp, "%13.6g ",
689 fabs(row->pval) <= 1e-9 ? 0.0 : row->pval);
690 if (row->type == GLP_LO || row->type == GLP_DB ||
691 row->type == GLP_FX)
692 xfprintf(fp, "%13.6g ", row->lb);
693 else
694 xfprintf(fp, "%13s ", "");
695 if (row->type == GLP_UP || row->type == GLP_DB)
696 xfprintf(fp, "%13.6g ", row->ub);
697 else
698 xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
699 if (fabs(row->dval) <= 1e-9)
700 xfprintf(fp, "%13s", "< eps");
701 else
702 xfprintf(fp, "%13.6g ", row->dval);
703 xfprintf(fp, "\n");
704 }
705 xfprintf(fp, "\n");
706 xfprintf(fp, " No. Column name Activity Lower bound "
707 " Upper bound Marginal\n");
708 xfprintf(fp, "------ ------------ ------------- ------------- "
709 "------------- -------------\n");
710 for (j = 1; j <= P->n; j++)
711 { col = P->col[j];
712 xfprintf(fp, "%6d ", j);
713 if (col->name == NULL || strlen(col->name) <= 12)
714 xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
715 else
716 xfprintf(fp, "%s\n%20s", col->name, "");
717 xfprintf(fp, "%3s", "");
718 xfprintf(fp, "%13.6g ",
719 fabs(col->pval) <= 1e-9 ? 0.0 : col->pval);
720 if (col->type == GLP_LO || col->type == GLP_DB ||
721 col->type == GLP_FX)
722 xfprintf(fp, "%13.6g ", col->lb);
723 else
724 xfprintf(fp, "%13s ", "");
725 if (col->type == GLP_UP || col->type == GLP_DB)
726 xfprintf(fp, "%13.6g ", col->ub);
727 else
728 xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
729 if (fabs(col->dval) <= 1e-9)
730 xfprintf(fp, "%13s", "< eps");
731 else
732 xfprintf(fp, "%13.6g ", col->dval);
733 xfprintf(fp, "\n");
734 }
735 xfprintf(fp, "\n");
736 xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
737 xfprintf(fp, "\n");
738 _glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
739 &re_ind);
740 xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
741 ae_max, ae_ind);
742 xfprintf(fp, " max.rel.err = %.2e on row %d\n",
743 re_max, re_ind);
744 xfprintf(fp, "%8s%s\n", "",
745 re_max <= 1e-9 ? "High quality" :
746 re_max <= 1e-6 ? "Medium quality" :
747 re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
748 xfprintf(fp, "\n");
749 _glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
750 &re_ind);
751 xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
752 ae_max, ae_ind <= P->m ? "row" : "column",
753 ae_ind <= P->m ? ae_ind : ae_ind - P->m);
754 xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
755 re_max, re_ind <= P->m ? "row" : "column",
756 re_ind <= P->m ? re_ind : re_ind - P->m);
757 xfprintf(fp, "%8s%s\n", "",
758 re_max <= 1e-9 ? "High quality" :
759 re_max <= 1e-6 ? "Medium quality" :
760 re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
761 "E");
762 xfprintf(fp, "\n");
763 _glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
764 &re_ind);
765 xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
766 ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
767 xfprintf(fp, " max.rel.err = %.2e on column %d\n",
768 re_max, re_ind == 0 ? 0 : re_ind - P->m);
769 xfprintf(fp, "%8s%s\n", "",
770 re_max <= 1e-9 ? "High quality" :
771 re_max <= 1e-6 ? "Medium quality" :
772 re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
773 xfprintf(fp, "\n");
774 _glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
775 &re_ind);
776 xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
777 ae_max, ae_ind <= P->m ? "row" : "column",
778 ae_ind <= P->m ? ae_ind : ae_ind - P->m);
779 xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
780 re_max, re_ind <= P->m ? "row" : "column",
781 re_ind <= P->m ? re_ind : re_ind - P->m);
782 xfprintf(fp, "%8s%s\n", "",
783 re_max <= 1e-9 ? "High quality" :
784 re_max <= 1e-6 ? "Medium quality" :
785 re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
786 ;
787 xfprintf(fp, "\n");
788 xfprintf(fp, "End of output\n");
789 xfflush(fp);
790 if (xferror(fp))
791 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
792 ret = 1;
793 goto done;
794 }
795 ret = 0;
796 done: if (fp != NULL) xfclose(fp);
797 return ret;
798 }
800 /***********************************************************************
801 * NAME
802 *
803 * glp_read_ipt - read interior-point solution from text file
804 *
805 * SYNOPSIS
806 *
807 * int glp_read_ipt(glp_prob *lp, const char *fname);
808 *
809 * DESCRIPTION
810 *
811 * The routine glp_read_ipt reads interior-point solution from a text
812 * file whose name is specified by the parameter fname into the problem
813 * object.
814 *
815 * For the file format see description of the routine glp_write_ipt.
816 *
817 * RETURNS
818 *
819 * On success the routine returns zero, otherwise non-zero. */
821 int glp_read_ipt(glp_prob *lp, const char *fname)
822 { glp_data *data;
823 jmp_buf jump;
824 int i, j, k, ret = 0;
825 xprintf("Reading interior-point solution from `%s'...\n", fname);
826 data = glp_sdf_open_file(fname);
827 if (data == NULL)
828 { ret = 1;
829 goto done;
830 }
831 if (setjmp(jump))
832 { ret = 1;
833 goto done;
834 }
835 glp_sdf_set_jump(data, jump);
836 /* number of rows, number of columns */
837 k = glp_sdf_read_int(data);
838 if (k != lp->m)
839 glp_sdf_error(data, "wrong number of rows\n");
840 k = glp_sdf_read_int(data);
841 if (k != lp->n)
842 glp_sdf_error(data, "wrong number of columns\n");
843 /* solution status, objective value */
844 k = glp_sdf_read_int(data);
845 if (!(k == GLP_UNDEF || k == GLP_OPT))
846 glp_sdf_error(data, "invalid solution status\n");
847 lp->ipt_stat = k;
848 lp->ipt_obj = glp_sdf_read_num(data);
849 /* rows (auxiliary variables) */
850 for (i = 1; i <= lp->m; i++)
851 { GLPROW *row = lp->row[i];
852 /* primal value, dual value */
853 row->pval = glp_sdf_read_num(data);
854 row->dval = glp_sdf_read_num(data);
855 }
856 /* columns (structural variables) */
857 for (j = 1; j <= lp->n; j++)
858 { GLPCOL *col = lp->col[j];
859 /* primal value, dual value */
860 col->pval = glp_sdf_read_num(data);
861 col->dval = glp_sdf_read_num(data);
862 }
863 xprintf("%d lines were read\n", glp_sdf_line(data));
864 done: if (ret) lp->ipt_stat = GLP_UNDEF;
865 if (data != NULL) glp_sdf_close_file(data);
866 return ret;
867 }
869 /***********************************************************************
870 * NAME
871 *
872 * glp_write_ipt - write interior-point solution to text file
873 *
874 * SYNOPSIS
875 *
876 * int glp_write_ipt(glp_prob *lp, const char *fname);
877 *
878 * DESCRIPTION
879 *
880 * The routine glp_write_ipt writes the current interior-point solution
881 * to a text file whose name is specified by the parameter fname. This
882 * file can be read back with the routine glp_read_ipt.
883 *
884 * RETURNS
885 *
886 * On success the routine returns zero, otherwise non-zero.
887 *
888 * FILE FORMAT
889 *
890 * The file created by the routine glp_write_ipt is a plain text file,
891 * which contains the following information:
892 *
893 * m n
894 * stat obj_val
895 * r_prim[1] r_dual[1]
896 * . . .
897 * r_prim[m] r_dual[m]
898 * c_prim[1] c_dual[1]
899 * . . .
900 * c_prim[n] c_dual[n]
901 *
902 * where:
903 * m is the number of rows (auxiliary variables);
904 * n is the number of columns (structural variables);
905 * stat is the solution status (GLP_UNDEF = 1 or GLP_OPT = 5);
906 * obj_val is the objective value;
907 * r_prim[i], i = 1,...,m, is the primal value of i-th row;
908 * r_dual[i], i = 1,...,m, is the dual value of i-th row;
909 * c_prim[j], j = 1,...,n, is the primal value of j-th column;
910 * c_dual[j], j = 1,...,n, is the dual value of j-th column. */
912 int glp_write_ipt(glp_prob *lp, const char *fname)
913 { XFILE *fp;
914 int i, j, ret = 0;
915 xprintf("Writing interior-point solution to `%s'...\n", fname);
916 fp = xfopen(fname, "w");
917 if (fp == NULL)
918 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
919 ret = 1;
920 goto done;
921 }
922 /* number of rows, number of columns */
923 xfprintf(fp, "%d %d\n", lp->m, lp->n);
924 /* solution status, objective value */
925 xfprintf(fp, "%d %.*g\n", lp->ipt_stat, DBL_DIG, lp->ipt_obj);
926 /* rows (auxiliary variables) */
927 for (i = 1; i <= lp->m; i++)
928 { GLPROW *row = lp->row[i];
929 /* primal value, dual value */
930 xfprintf(fp, "%.*g %.*g\n", DBL_DIG, row->pval, DBL_DIG,
931 row->dval);
932 }
933 /* columns (structural variables) */
934 for (j = 1; j <= lp->n; j++)
935 { GLPCOL *col = lp->col[j];
936 /* primal value, dual value */
937 xfprintf(fp, "%.*g %.*g\n", DBL_DIG, col->pval, DBL_DIG,
938 col->dval);
939 }
940 xfflush(fp);
941 if (xferror(fp))
942 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
943 ret = 1;
944 goto done;
945 }
946 xprintf("%d lines were written\n", 2 + lp->m + lp->n);
947 done: if (fp != NULL) xfclose(fp);
948 return ret;
949 }
951 /**********************************************************************/
953 int glp_print_mip(glp_prob *P, const char *fname)
954 { /* write MIP solution in printable format */
955 XFILE *fp;
956 GLPROW *row;
957 GLPCOL *col;
958 int i, j, t, ae_ind, re_ind, ret;
959 double ae_max, re_max;
960 xprintf("Writing MIP solution 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, "%-12s%s\n", "Problem:",
968 P->name == NULL ? "" : P->name);
969 xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
970 xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:",
971 P->n, glp_get_num_int(P), glp_get_num_bin(P));
972 xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
973 t = glp_mip_status(P);
974 xfprintf(fp, "%-12s%s\n", "Status:",
975 t == GLP_OPT ? "INTEGER OPTIMAL" :
976 t == GLP_FEAS ? "INTEGER NON-OPTIMAL" :
977 t == GLP_NOFEAS ? "INTEGER EMPTY" :
978 t == GLP_UNDEF ? "INTEGER UNDEFINED" : "???");
979 xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
980 P->obj == NULL ? "" : P->obj,
981 P->obj == NULL ? "" : " = ", P->mip_obj,
982 P->dir == GLP_MIN ? "MINimum" :
983 P->dir == GLP_MAX ? "MAXimum" : "???");
984 xfprintf(fp, "\n");
985 xfprintf(fp, " No. Row name Activity Lower bound "
986 " Upper bound\n");
987 xfprintf(fp, "------ ------------ ------------- ------------- "
988 "-------------\n");
989 for (i = 1; i <= P->m; i++)
990 { row = P->row[i];
991 xfprintf(fp, "%6d ", i);
992 if (row->name == NULL || strlen(row->name) <= 12)
993 xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
994 else
995 xfprintf(fp, "%s\n%20s", row->name, "");
996 xfprintf(fp, "%3s", "");
997 xfprintf(fp, "%13.6g ",
998 fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx);
999 if (row->type == GLP_LO || row->type == GLP_DB ||
1000 row->type == GLP_FX)
1001 xfprintf(fp, "%13.6g ", row->lb);
1002 else
1003 xfprintf(fp, "%13s ", "");
1004 if (row->type == GLP_UP || row->type == GLP_DB)
1005 xfprintf(fp, "%13.6g ", row->ub);
1006 else
1007 xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
1008 xfprintf(fp, "\n");
1010 xfprintf(fp, "\n");
1011 xfprintf(fp, " No. Column name Activity Lower bound "
1012 " Upper bound\n");
1013 xfprintf(fp, "------ ------------ ------------- ------------- "
1014 "-------------\n");
1015 for (j = 1; j <= P->n; j++)
1016 { col = P->col[j];
1017 xfprintf(fp, "%6d ", j);
1018 if (col->name == NULL || strlen(col->name) <= 12)
1019 xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
1020 else
1021 xfprintf(fp, "%s\n%20s", col->name, "");
1022 xfprintf(fp, "%s ",
1023 col->kind == GLP_CV ? " " :
1024 col->kind == GLP_IV ? "*" : "?");
1025 xfprintf(fp, "%13.6g ",
1026 fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx);
1027 if (col->type == GLP_LO || col->type == GLP_DB ||
1028 col->type == GLP_FX)
1029 xfprintf(fp, "%13.6g ", col->lb);
1030 else
1031 xfprintf(fp, "%13s ", "");
1032 if (col->type == GLP_UP || col->type == GLP_DB)
1033 xfprintf(fp, "%13.6g ", col->ub);
1034 else
1035 xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
1036 xfprintf(fp, "\n");
1038 xfprintf(fp, "\n");
1039 xfprintf(fp, "Integer feasibility conditions:\n");
1040 xfprintf(fp, "\n");
1041 _glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
1042 &re_ind);
1043 xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
1044 ae_max, ae_ind);
1045 xfprintf(fp, " max.rel.err = %.2e on row %d\n",
1046 re_max, re_ind);
1047 xfprintf(fp, "%8s%s\n", "",
1048 re_max <= 1e-9 ? "High quality" :
1049 re_max <= 1e-6 ? "Medium quality" :
1050 re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG");
1051 xfprintf(fp, "\n");
1052 _glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
1053 &re_ind);
1054 xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
1055 ae_max, ae_ind <= P->m ? "row" : "column",
1056 ae_ind <= P->m ? ae_ind : ae_ind - P->m);
1057 xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
1058 re_max, re_ind <= P->m ? "row" : "column",
1059 re_ind <= P->m ? re_ind : re_ind - P->m);
1060 xfprintf(fp, "%8s%s\n", "",
1061 re_max <= 1e-9 ? "High quality" :
1062 re_max <= 1e-6 ? "Medium quality" :
1063 re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE");
1064 xfprintf(fp, "\n");
1065 xfprintf(fp, "End of output\n");
1066 xfflush(fp);
1067 if (xferror(fp))
1068 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
1069 ret = 1;
1070 goto done;
1072 ret = 0;
1073 done: if (fp != NULL) xfclose(fp);
1074 return ret;
1077 /***********************************************************************
1078 * NAME
1080 * glp_read_mip - read MIP solution from text file
1082 * SYNOPSIS
1084 * int glp_read_mip(glp_prob *mip, const char *fname);
1086 * DESCRIPTION
1088 * The routine glp_read_mip reads MIP solution from a text file whose
1089 * name is specified by the parameter fname into the problem object.
1091 * For the file format see description of the routine glp_write_mip.
1093 * RETURNS
1095 * On success the routine returns zero, otherwise non-zero. */
1097 int glp_read_mip(glp_prob *mip, const char *fname)
1098 { glp_data *data;
1099 jmp_buf jump;
1100 int i, j, k, ret = 0;
1101 xprintf("Reading MIP solution from `%s'...\n", fname);
1102 data = glp_sdf_open_file(fname);
1103 if (data == NULL)
1104 { ret = 1;
1105 goto done;
1107 if (setjmp(jump))
1108 { ret = 1;
1109 goto done;
1111 glp_sdf_set_jump(data, jump);
1112 /* number of rows, number of columns */
1113 k = glp_sdf_read_int(data);
1114 if (k != mip->m)
1115 glp_sdf_error(data, "wrong number of rows\n");
1116 k = glp_sdf_read_int(data);
1117 if (k != mip->n)
1118 glp_sdf_error(data, "wrong number of columns\n");
1119 /* solution status, objective value */
1120 k = glp_sdf_read_int(data);
1121 if (!(k == GLP_UNDEF || k == GLP_OPT || k == GLP_FEAS ||
1122 k == GLP_NOFEAS))
1123 glp_sdf_error(data, "invalid solution status\n");
1124 mip->mip_stat = k;
1125 mip->mip_obj = glp_sdf_read_num(data);
1126 /* rows (auxiliary variables) */
1127 for (i = 1; i <= mip->m; i++)
1128 { GLPROW *row = mip->row[i];
1129 row->mipx = glp_sdf_read_num(data);
1131 /* columns (structural variables) */
1132 for (j = 1; j <= mip->n; j++)
1133 { GLPCOL *col = mip->col[j];
1134 col->mipx = glp_sdf_read_num(data);
1135 if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
1136 glp_sdf_error(data, "non-integer column value");
1138 xprintf("%d lines were read\n", glp_sdf_line(data));
1139 done: if (ret) mip->mip_stat = GLP_UNDEF;
1140 if (data != NULL) glp_sdf_close_file(data);
1141 return ret;
1144 /***********************************************************************
1145 * NAME
1147 * glp_write_mip - write MIP solution to text file
1149 * SYNOPSIS
1151 * int glp_write_mip(glp_prob *mip, const char *fname);
1153 * DESCRIPTION
1155 * The routine glp_write_mip writes the current MIP solution to a text
1156 * file whose name is specified by the parameter fname. This file can
1157 * be read back with the routine glp_read_mip.
1159 * RETURNS
1161 * On success the routine returns zero, otherwise non-zero.
1163 * FILE FORMAT
1165 * The file created by the routine glp_write_sol is a plain text file,
1166 * which contains the following information:
1168 * m n
1169 * stat obj_val
1170 * r_val[1]
1171 * . . .
1172 * r_val[m]
1173 * c_val[1]
1174 * . . .
1175 * c_val[n]
1177 * where:
1178 * m is the number of rows (auxiliary variables);
1179 * n is the number of columns (structural variables);
1180 * stat is the solution status (GLP_UNDEF = 1, GLP_FEAS = 2,
1181 * GLP_NOFEAS = 4, or GLP_OPT = 5);
1182 * obj_val is the objective value;
1183 * r_val[i], i = 1,...,m, is the value of i-th row;
1184 * c_val[j], j = 1,...,n, is the value of j-th column. */
1186 int glp_write_mip(glp_prob *mip, const char *fname)
1187 { XFILE *fp;
1188 int i, j, ret = 0;
1189 xprintf("Writing MIP solution to `%s'...\n", fname);
1190 fp = xfopen(fname, "w");
1191 if (fp == NULL)
1192 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
1193 ret = 1;
1194 goto done;
1196 /* number of rows, number of columns */
1197 xfprintf(fp, "%d %d\n", mip->m, mip->n);
1198 /* solution status, objective value */
1199 xfprintf(fp, "%d %.*g\n", mip->mip_stat, DBL_DIG, mip->mip_obj);
1200 /* rows (auxiliary variables) */
1201 for (i = 1; i <= mip->m; i++)
1202 xfprintf(fp, "%.*g\n", DBL_DIG, mip->row[i]->mipx);
1203 /* columns (structural variables) */
1204 for (j = 1; j <= mip->n; j++)
1205 xfprintf(fp, "%.*g\n", DBL_DIG, mip->col[j]->mipx);
1206 xfflush(fp);
1207 if (xferror(fp))
1208 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
1209 ret = 1;
1210 goto done;
1212 xprintf("%d lines were written\n", 2 + mip->m + mip->n);
1213 done: if (fp != NULL) xfclose(fp);
1214 return ret;
1217 /* eof */