1 /* glpapi11.c (utility routines) */
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
9 * E-mail: <mao@gnu.org>.
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.
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.
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 ***********************************************************************/
27 int glp_print_sol(glp_prob *P, const char *fname)
28 { /* write basic solution in printable format */
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");
37 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
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" : "???");
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++)
66 xfprintf(fp, "%6d ", i);
67 if (row->name == NULL || strlen(row->name) <= 12)
68 xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
70 xfprintf(fp, "%s\n%20s", row->name, "");
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 ||
81 xfprintf(fp, "%13.6g ", row->lb);
83 xfprintf(fp, "%13s ", "");
84 if (row->type == GLP_UP || row->type == GLP_DB)
85 xfprintf(fp, "%13.6g ", row->ub);
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");
92 xfprintf(fp, "%13.6g ", row->dual);
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++)
103 xfprintf(fp, "%6d ", j);
104 if (col->name == NULL || strlen(col->name) <= 12)
105 xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
107 xfprintf(fp, "%s\n%20s", col->name, "");
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 ||
118 xfprintf(fp, "%13.6g ", col->lb);
120 xfprintf(fp, "%13s ", "");
121 if (col->type == GLP_UP || col->type == GLP_DB)
122 xfprintf(fp, "%13.6g ", col->ub);
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");
129 xfprintf(fp, "%13.6g ", col->dual);
134 xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
136 _glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
138 xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
140 xfprintf(fp, " max.rel.err = %.2e on row %d\n",
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");
147 _glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
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"
161 _glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
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");
172 _glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
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")
186 xfprintf(fp, "End of output\n");
189 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
194 done: if (fp != NULL) xfclose(fp);
198 /***********************************************************************
201 * glp_read_sol - read basic solution from text file
205 * int glp_read_sol(glp_prob *lp, const char *fname);
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.
212 * For the file format see description of the routine glp_write_sol.
216 * On success the routine returns zero, otherwise non-zero. */
218 int glp_read_sol(glp_prob *lp, const char *fname)
221 int i, j, k, ret = 0;
222 xprintf("Reading basic solution from `%s'...\n", fname);
223 data = glp_sdf_open_file(fname);
232 glp_sdf_set_jump(data, jump);
233 /* number of rows, number of columns */
234 k = glp_sdf_read_int(data);
236 glp_sdf_error(data, "wrong number of rows\n");
237 k = glp_sdf_read_int(data);
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 ||
244 glp_sdf_error(data, "invalid primal status\n");
246 k = glp_sdf_read_int(data);
247 if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
249 glp_sdf_error(data, "invalid dual status\n");
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);
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);
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);
282 /***********************************************************************
285 * glp_write_sol - write basic solution to text file
289 * int glp_write_sol(glp_prob *lp, const char *fname);
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.
299 * On success the routine returns zero, otherwise non-zero.
303 * The file created by the routine glp_write_sol is a plain text file,
304 * which contains the following information:
307 * p_stat d_stat obj_val
308 * r_stat[1] r_prim[1] r_dual[1]
310 * r_stat[m] r_prim[m] r_dual[m]
311 * c_stat[1] c_prim[1] c_dual[1]
313 * c_stat[n] c_prim[n] c_dual[n]
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)
335 xprintf("Writing basic solution to `%s'...\n", fname);
336 fp = xfopen(fname, "w");
338 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
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,
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,
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,
363 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
367 xprintf("%d lines were written\n", 2 + lp->m + lp->n);
368 done: if (fp != NULL) xfclose(fp);
372 /**********************************************************************/
374 static char *format(char buf[13+1], double x)
375 { /* format floating-point number in MPS/360-like style */
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);
383 if (strcmp(buf, " 0.00000") == 0 ||
384 strcmp(buf, " -0.00000") == 0)
386 else if (memcmp(buf, " 0.", 8) == 0)
387 memcpy(buf, " .", 8);
388 else if (memcmp(buf, " -0.", 8) == 0)
389 memcpy(buf, " -.", 8);
393 sprintf(buf, "%13.6g", x);
397 int glp_print_ranges(glp_prob *P, int len, const int list[],
398 int flags, const char *fname)
399 { /* print sensitivity analysis report */
403 int m, n, pass, k, t, numb, type, stat, var1, var2, count, page,
405 double lb, ub, slack, coef, prim, dual, value1, value2, coef1,
407 const char *name, *limit;
410 if (P == NULL || P->magic != GLP_PROB_MAGIC)
411 xerror("glp_print_ranges: P = %p; invalid problem object\n",
415 xerror("glp_print_ranges: len = %d; invalid list length\n",
419 xerror("glp_print_ranges: list = %p: invalid parameter\n",
421 for (t = 1; t <= len; 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);
429 xerror("glp_print_ranges: flags = %d; invalid parameter\n",
432 xerror("glp_print_ranges: fname = %p; invalid parameter\n",
434 if (glp_get_status(P) != GLP_OPT)
435 { xprintf("glp_print_ranges: optimal basic solution required\n");
439 if (!glp_bf_exists(P))
440 { xprintf("glp_print_ranges: basis factorization required\n");
444 /* start reporting */
445 xprintf("Write sensitivity analysis report to `%s'...\n", fname);
446 fp = xfopen(fname, "w");
448 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
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)
460 { xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa"
461 "ge%4d\n", glp_version(), "", ++page);
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" : "???");
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",
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");
485 xassert(1 <= numb && numb <= m);
489 lb = glp_get_row_lb(P, numb);
490 ub = glp_get_row_ub(P, numb);
496 else if (type == GLP_LO)
498 else if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
504 xassert(1 <= numb && numb <= n);
507 lb = glp_get_col_lb(P, numb);
508 ub = glp_get_col_ub(P, numb);
516 { glp_analyze_bound(P, k, &value1, &var1, &value2, &var2);
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;
525 coef1 = -DBL_MAX, coef2 = coef - dual;
526 if (value1 == -DBL_MAX)
529 else if (dual > +1e-9)
535 obj1 = P->obj_val + dual * (value1 - prim);
536 if (value2 == +DBL_MAX)
539 else if (dual > +1e-9)
545 obj2 = P->obj_val + dual * (value2 - prim);
548 { glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2,
550 if (coef1 == -DBL_MAX)
553 else if (prim > +1e-9)
559 obj1 = P->obj_val + (coef1 - coef) * prim;
560 if (coef2 == +DBL_MAX)
563 else if (prim > +1e-9)
569 obj2 = P->obj_val + (coef2 - coef) * prim;
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 */
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 */
598 limit = glp_get_row_name(P, var1);
600 limit = glp_get_col_name(P, var1 - m);
602 xfprintf(fp, " %s", limit);
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 */
620 limit = glp_get_row_name(P, var2);
622 limit = glp_get_col_name(P, var2 - m);
624 xfprintf(fp, " %s", limit);
628 /* print 10 items per page */
629 count = (count + 1) % 10;
631 xfprintf(fp, "End of report\n");
634 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
639 done: if (fp != NULL) xfclose(fp);
643 /**********************************************************************/
645 int glp_print_ipt(glp_prob *P, const char *fname)
646 { /* write interior-point solution in printable format */
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");
655 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
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" : "???");
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++)
682 xfprintf(fp, "%6d ", i);
683 if (row->name == NULL || strlen(row->name) <= 12)
684 xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
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 ||
692 xfprintf(fp, "%13.6g ", row->lb);
694 xfprintf(fp, "%13s ", "");
695 if (row->type == GLP_UP || row->type == GLP_DB)
696 xfprintf(fp, "%13.6g ", row->ub);
698 xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
699 if (fabs(row->dval) <= 1e-9)
700 xfprintf(fp, "%13s", "< eps");
702 xfprintf(fp, "%13.6g ", row->dval);
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++)
712 xfprintf(fp, "%6d ", j);
713 if (col->name == NULL || strlen(col->name) <= 12)
714 xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
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 ||
722 xfprintf(fp, "%13.6g ", col->lb);
724 xfprintf(fp, "%13s ", "");
725 if (col->type == GLP_UP || col->type == GLP_DB)
726 xfprintf(fp, "%13.6g ", col->ub);
728 xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
729 if (fabs(col->dval) <= 1e-9)
730 xfprintf(fp, "%13s", "< eps");
732 xfprintf(fp, "%13.6g ", col->dval);
736 xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
738 _glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
740 xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
742 xfprintf(fp, " max.rel.err = %.2e on row %d\n",
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");
749 _glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
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"
763 _glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
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");
774 _glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
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")
788 xfprintf(fp, "End of output\n");
791 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
796 done: if (fp != NULL) xfclose(fp);
800 /***********************************************************************
803 * glp_read_ipt - read interior-point solution from text file
807 * int glp_read_ipt(glp_prob *lp, const char *fname);
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
815 * For the file format see description of the routine glp_write_ipt.
819 * On success the routine returns zero, otherwise non-zero. */
821 int glp_read_ipt(glp_prob *lp, const char *fname)
824 int i, j, k, ret = 0;
825 xprintf("Reading interior-point solution from `%s'...\n", fname);
826 data = glp_sdf_open_file(fname);
835 glp_sdf_set_jump(data, jump);
836 /* number of rows, number of columns */
837 k = glp_sdf_read_int(data);
839 glp_sdf_error(data, "wrong number of rows\n");
840 k = glp_sdf_read_int(data);
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");
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);
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);
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);
869 /***********************************************************************
872 * glp_write_ipt - write interior-point solution to text file
876 * int glp_write_ipt(glp_prob *lp, const char *fname);
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.
886 * On success the routine returns zero, otherwise non-zero.
890 * The file created by the routine glp_write_ipt is a plain text file,
891 * which contains the following information:
895 * r_prim[1] r_dual[1]
897 * r_prim[m] r_dual[m]
898 * c_prim[1] c_dual[1]
900 * c_prim[n] c_dual[n]
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)
915 xprintf("Writing interior-point solution to `%s'...\n", fname);
916 fp = xfopen(fname, "w");
918 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
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,
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,
942 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
946 xprintf("%d lines were written\n", 2 + lp->m + lp->n);
947 done: if (fp != NULL) xfclose(fp);
951 /**********************************************************************/
953 int glp_print_mip(glp_prob *P, const char *fname)
954 { /* write MIP solution in printable format */
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");
963 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
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" : "???");
985 xfprintf(fp, " No. Row name Activity Lower bound "
987 xfprintf(fp, "------ ------------ ------------- ------------- "
989 for (i = 1; i <= P->m; i++)
991 xfprintf(fp, "%6d ", i);
992 if (row->name == NULL || strlen(row->name) <= 12)
993 xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
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);
1003 xfprintf(fp, "%13s ", "");
1004 if (row->type == GLP_UP || row->type == GLP_DB)
1005 xfprintf(fp, "%13.6g ", row->ub);
1007 xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
1011 xfprintf(fp, " No. Column name Activity Lower bound "
1013 xfprintf(fp, "------ ------------ ------------- ------------- "
1015 for (j = 1; j <= P->n; j++)
1017 xfprintf(fp, "%6d ", j);
1018 if (col->name == NULL || strlen(col->name) <= 12)
1019 xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
1021 xfprintf(fp, "%s\n%20s", col->name, "");
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);
1031 xfprintf(fp, "%13s ", "");
1032 if (col->type == GLP_UP || col->type == GLP_DB)
1033 xfprintf(fp, "%13.6g ", col->ub);
1035 xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
1039 xfprintf(fp, "Integer feasibility conditions:\n");
1041 _glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
1043 xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
1045 xfprintf(fp, " max.rel.err = %.2e on row %d\n",
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");
1052 _glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
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");
1065 xfprintf(fp, "End of output\n");
1068 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
1073 done: if (fp != NULL) xfclose(fp);
1077 /***********************************************************************
1080 * glp_read_mip - read MIP solution from text file
1084 * int glp_read_mip(glp_prob *mip, const char *fname);
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.
1095 * On success the routine returns zero, otherwise non-zero. */
1097 int glp_read_mip(glp_prob *mip, const char *fname)
1100 int i, j, k, ret = 0;
1101 xprintf("Reading MIP solution from `%s'...\n", fname);
1102 data = glp_sdf_open_file(fname);
1111 glp_sdf_set_jump(data, jump);
1112 /* number of rows, number of columns */
1113 k = glp_sdf_read_int(data);
1115 glp_sdf_error(data, "wrong number of rows\n");
1116 k = glp_sdf_read_int(data);
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 ||
1123 glp_sdf_error(data, "invalid solution status\n");
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);
1144 /***********************************************************************
1147 * glp_write_mip - write MIP solution to text file
1151 * int glp_write_mip(glp_prob *mip, const char *fname);
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.
1161 * On success the routine returns zero, otherwise non-zero.
1165 * The file created by the routine glp_write_sol is a plain text file,
1166 * which contains the following information:
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)
1189 xprintf("Writing MIP solution to `%s'...\n", fname);
1190 fp = xfopen(fname, "w");
1192 { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
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);
1208 { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
1212 xprintf("%d lines were written\n", 2 + mip->m + mip->n);
1213 done: if (fp != NULL) xfclose(fp);