PageRenderTime 81ms CodeModel.GetById 19ms app.highlight 54ms RepoModel.GetById 1ms app.codeStats 0ms

/farmR/src/glpapi11.c

https://code.google.com/p/javawfm/
C | 967 lines | 701 code | 20 blank | 246 comment | 260 complexity | c5ca2f35d221beda9e37806526fbcd07 MD5 | raw file
  1/* glpapi11.c (utility routines) */
  2
  3/***********************************************************************
  4*  This code is part of GLPK (GNU Linear Programming Kit).
  5*
  6*  Copyright (C) 2000,01,02,03,04,05,06,07,08,2009 Andrew Makhorin,
  7*  Department for Applied Informatics, Moscow Aviation Institute,
  8*  Moscow, Russia. All rights reserved. E-mail: <mao@mai2.rcnet.ru>.
  9*
 10*  GLPK is free software: you can redistribute it and/or modify it
 11*  under the terms of the GNU General Public License as published by
 12*  the Free Software Foundation, either version 3 of the License, or
 13*  (at your option) any later version.
 14*
 15*  GLPK is distributed in the hope that it will be useful, but WITHOUT
 16*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 17*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
 18*  License for more details.
 19*
 20*  You should have received a copy of the GNU General Public License
 21*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
 22***********************************************************************/
 23
 24#include "glpapi.h"
 25#define PDS _glp_data
 26#define pds_open_file _glp_sds_open
 27#define pds_set_jump _glp_sds_jump
 28#define pds_error _glp_sds_error
 29#define pds_scan_int _glp_sds_int
 30#define pds_scan_num _glp_sds_num
 31#define pds_close_file _glp_sds_close
 32#undef FILE
 33#define FILE XFILE
 34#undef fopen
 35#define fopen xfopen
 36#undef strerror
 37#define strerror(errno) xerrmsg()
 38#undef fprintf
 39#define fprintf xfprintf
 40#undef fflush
 41#define fflush xfflush
 42#undef ferror
 43#define ferror xferror
 44#undef fclose
 45#define fclose xfclose
 46
 47int glp_print_sol(glp_prob *P, const char *fname)
 48{     /* write basic solution in printable format */
 49      XFILE *fp;
 50      GLPROW *row;
 51      GLPCOL *col;
 52      int i, j, t, ae_ind, re_ind, ret;
 53      double ae_max, re_max;
 54      xprintf("Writing basic solution to `%s'...\n", fname);
 55      fp = xfopen(fname, "w");
 56      if (fp == NULL)
 57      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 58         ret = 1;
 59         goto done;
 60      }
 61      xfprintf(fp, "%-12s%s\n", "Problem:",
 62         P->name == NULL ? "" : P->name);
 63      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
 64      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
 65      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
 66      t = glp_get_status(P);
 67      xfprintf(fp, "%-12s%s\n", "Status:",
 68         t == GLP_OPT    ? "OPTIMAL" :
 69         t == GLP_FEAS   ? "FEASIBLE" :
 70         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
 71         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" :
 72         t == GLP_UNBND  ? "UNBOUNDED" :
 73         t == GLP_UNDEF  ? "UNDEFINED" : "???");
 74      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
 75         P->obj == NULL ? "" : P->obj,
 76         P->obj == NULL ? "" : " = ", P->obj_val,
 77         P->dir == GLP_MIN ? "MINimum" :
 78         P->dir == GLP_MAX ? "MAXimum" : "???");
 79      xfprintf(fp, "\n");
 80      xfprintf(fp, "   No.   Row name   St   Activity     Lower bound  "
 81         " Upper bound    Marginal\n");
 82      xfprintf(fp, "------ ------------ -- ------------- ------------- "
 83         "------------- -------------\n");
 84      for (i = 1; i <= P->m; i++)
 85      {  row = P->row[i];
 86         xfprintf(fp, "%6d ", i);
 87         if (row->name == NULL || strlen(row->name) <= 12)
 88            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
 89         else
 90            xfprintf(fp, "%s\n%20s", row->name, "");
 91         xfprintf(fp, "%s ",
 92            row->stat == GLP_BS ? "B " :
 93            row->stat == GLP_NL ? "NL" :
 94            row->stat == GLP_NU ? "NU" :
 95            row->stat == GLP_NF ? "NF" :
 96            row->stat == GLP_NS ? "NS" : "??");
 97         xfprintf(fp, "%13.6g ",
 98            fabs(row->prim) <= 1e-9 ? 0.0 : row->prim);
 99         if (row->type == GLP_LO || row->type == GLP_DB ||
100             row->type == GLP_FX)
101            xfprintf(fp, "%13.6g ", row->lb);
102         else
103            xfprintf(fp, "%13s ", "");
104         if (row->type == GLP_UP || row->type == GLP_DB)
105            xfprintf(fp, "%13.6g ", row->ub);
106         else
107            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
108         if (row->stat != GLP_BS)
109         {  if (fabs(row->dual) <= 1e-9)
110               xfprintf(fp, "%13s", "< eps");
111            else
112               xfprintf(fp, "%13.6g ", row->dual);
113         }
114         xfprintf(fp, "\n");
115      }
116      xfprintf(fp, "\n");
117      xfprintf(fp, "   No. Column name  St   Activity     Lower bound  "
118         " Upper bound    Marginal\n");
119      xfprintf(fp, "------ ------------ -- ------------- ------------- "
120         "------------- -------------\n");
121      for (j = 1; j <= P->n; j++)
122      {  col = P->col[j];
123         xfprintf(fp, "%6d ", j);
124         if (col->name == NULL || strlen(col->name) <= 12)
125            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
126         else
127            xfprintf(fp, "%s\n%20s", col->name, "");
128         xfprintf(fp, "%s ",
129            col->stat == GLP_BS ? "B " :
130            col->stat == GLP_NL ? "NL" :
131            col->stat == GLP_NU ? "NU" :
132            col->stat == GLP_NF ? "NF" :
133            col->stat == GLP_NS ? "NS" : "??");
134         xfprintf(fp, "%13.6g ",
135            fabs(col->prim) <= 1e-9 ? 0.0 : col->prim);
136         if (col->type == GLP_LO || col->type == GLP_DB ||
137             col->type == GLP_FX)
138            xfprintf(fp, "%13.6g ", col->lb);
139         else
140            xfprintf(fp, "%13s ", "");
141         if (col->type == GLP_UP || col->type == GLP_DB)
142            xfprintf(fp, "%13.6g ", col->ub);
143         else
144            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
145         if (col->stat != GLP_BS)
146         {  if (fabs(col->dual) <= 1e-9)
147               xfprintf(fp, "%13s", "< eps");
148            else
149               xfprintf(fp, "%13.6g ", col->dual);
150         }
151         xfprintf(fp, "\n");
152      }
153      xfprintf(fp, "\n");
154      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
155      xfprintf(fp, "\n");
156      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
157         &re_ind);
158      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
159         ae_max, ae_ind);
160      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
161         re_max, re_ind);
162      xfprintf(fp, "%8s%s\n", "",
163         re_max <= 1e-9 ? "High quality" :
164         re_max <= 1e-6 ? "Medium quality" :
165         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
166      xfprintf(fp, "\n");
167      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
168         &re_ind);
169      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
170            ae_max, ae_ind <= P->m ? "row" : "column",
171            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
172      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
173            re_max, re_ind <= P->m ? "row" : "column",
174            re_ind <= P->m ? re_ind : re_ind - P->m);
175      xfprintf(fp, "%8s%s\n", "",
176         re_max <= 1e-9 ? "High quality" :
177         re_max <= 1e-6 ? "Medium quality" :
178         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
179            "E");
180      xfprintf(fp, "\n");
181      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
182         &re_ind);
183      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
184         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
185      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
186         re_max, re_ind == 0 ? 0 : re_ind - P->m);
187      xfprintf(fp, "%8s%s\n", "",
188         re_max <= 1e-9 ? "High quality" :
189         re_max <= 1e-6 ? "Medium quality" :
190         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
191      xfprintf(fp, "\n");
192      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
193         &re_ind);
194      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
195            ae_max, ae_ind <= P->m ? "row" : "column",
196            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
197      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
198            re_max, re_ind <= P->m ? "row" : "column",
199            re_ind <= P->m ? re_ind : re_ind - P->m);
200      xfprintf(fp, "%8s%s\n", "",
201         re_max <= 1e-9 ? "High quality" :
202         re_max <= 1e-6 ? "Medium quality" :
203         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
204            ;
205      xfprintf(fp, "\n");
206      xfprintf(fp, "End of output\n");
207      xfflush(fp);
208      if (xferror(fp))
209      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
210         ret = 1;
211         goto done;
212      }
213      ret = 0;
214done: if (fp != NULL) xfclose(fp);
215      return ret;
216}
217
218/***********************************************************************
219*  NAME
220*
221*  glp_read_sol - read basic solution from text file
222*
223*  SYNOPSIS
224*
225*  int glp_read_sol(glp_prob *lp, const char *fname);
226*
227*  DESCRIPTION
228*
229*  The routine glp_read_sol reads basic solution from a text file whose
230*  name is specified by the parameter fname into the problem object.
231*
232*  For the file format see description of the routine glp_write_sol.
233*
234*  RETURNS
235*
236*  On success the routine returns zero, otherwise non-zero. */
237
238int glp_read_sol(glp_prob *lp, const char *fname)
239{     PDS *pds;
240      jmp_buf jump;
241      int i, j, k, ret = 0;
242      xprintf("Reading basic solution from `%s'...\n", fname);
243      pds = pds_open_file(fname);
244      if (pds == NULL)
245      {  ret = 1;
246         goto done;
247      }
248      if (setjmp(jump))
249      {  ret = 1;
250         goto done;
251      }
252      pds_set_jump(pds, jump);
253      /* number of rows, number of columns */
254      k = pds_scan_int(pds);
255      if (k != lp->m)
256         pds_error(pds, "wrong number of rows\n");
257      k = pds_scan_int(pds);
258      if (k != lp->n)
259         pds_error(pds, "wrong number of columns\n");
260      /* primal status, dual status, objective value */
261      k = pds_scan_int(pds);
262      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
263            k == GLP_NOFEAS))
264         pds_error(pds, "invalid primal status\n");
265      lp->pbs_stat = k;
266      k = pds_scan_int(pds);
267      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
268            k == GLP_NOFEAS))
269         pds_error(pds, "invalid dual status\n");
270      lp->dbs_stat = k;
271      lp->obj_val = pds_scan_num(pds);
272      /* rows (auxiliary variables) */
273      for (i = 1; i <= lp->m; i++)
274      {  GLPROW *row = lp->row[i];
275         /* status, primal value, dual value */
276         k = pds_scan_int(pds);
277         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
278               k == GLP_NF || k == GLP_NS))
279            pds_error(pds, "invalid row status\n");
280         glp_set_row_stat(lp, i, k);
281         row->prim = pds_scan_num(pds);
282         row->dual = pds_scan_num(pds);
283      }
284      /* columns (structural variables) */
285      for (j = 1; j <= lp->n; j++)
286      {  GLPCOL *col = lp->col[j];
287         /* status, primal value, dual value */
288         k = pds_scan_int(pds);
289         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
290               k == GLP_NF || k == GLP_NS))
291            pds_error(pds, "invalid column status\n");
292         glp_set_col_stat(lp, j, k);
293         col->prim = pds_scan_num(pds);
294         col->dual = pds_scan_num(pds);
295      }
296      xprintf("%d lines were read\n", _glp_sds_line(pds));
297done: if (ret) lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
298      if (pds != NULL) pds_close_file(pds);
299      return ret;
300}
301
302/***********************************************************************
303*  NAME
304*
305*  glp_write_sol - write basic solution to text file
306*
307*  SYNOPSIS
308*
309*  int glp_write_sol(glp_prob *lp, const char *fname);
310*
311*  DESCRIPTION
312*
313*  The routine glp_write_sol writes the current basic solution to a
314*  text file whose name is specified by the parameter fname. This file
315*  can be read back with the routine glp_read_sol.
316*
317*  RETURNS
318*
319*  On success the routine returns zero, otherwise non-zero.
320*
321*  FILE FORMAT
322*
323*  The file created by the routine glp_write_sol is a plain text file,
324*  which contains the following information:
325*
326*     m n
327*     p_stat d_stat obj_val
328*     r_stat[1] r_prim[1] r_dual[1]
329*     . . .
330*     r_stat[m] r_prim[m] r_dual[m]
331*     c_stat[1] c_prim[1] c_dual[1]
332*     . . .
333*     c_stat[n] c_prim[n] c_dual[n]
334*
335*  where:
336*  m is the number of rows (auxiliary variables);
337*  n is the number of columns (structural variables);
338*  p_stat is the primal status of the basic solution (GLP_UNDEF = 1,
339*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
340*  d_stat is the dual status of the basic solution (GLP_UNDEF = 1,
341*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
342*  obj_val is the objective value;
343*  r_stat[i], i = 1,...,m, is the status of i-th row (GLP_BS = 1,
344*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
345*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
346*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
347*  c_stat[j], j = 1,...,n, is the status of j-th column (GLP_BS = 1,
348*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
349*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
350*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
351
352int glp_write_sol(glp_prob *lp, const char *fname)
353{     FILE *fp;
354      int i, j, ret = 0;
355      xprintf("Writing basic solution to `%s'...\n", fname);
356      fp = fopen(fname, "w");
357      if (fp == NULL)
358      {  xprintf("Unable to create `%s' - %s\n", fname,
359            strerror(errno));
360         ret = 1;
361         goto done;
362      }
363      /* number of rows, number of columns */
364      fprintf(fp, "%d %d\n", lp->m, lp->n);
365      /* primal status, dual status, objective value */
366      fprintf(fp, "%d %d %.*g\n", lp->pbs_stat, lp->dbs_stat, DBL_DIG,
367         lp->obj_val);
368      /* rows (auxiliary variables) */
369      for (i = 1; i <= lp->m; i++)
370      {  GLPROW *row = lp->row[i];
371         /* status, primal value, dual value */
372         fprintf(fp, "%d %.*g %.*g\n", row->stat, DBL_DIG, row->prim,
373            DBL_DIG, row->dual);
374      }
375      /* columns (structural variables) */
376      for (j = 1; j <= lp->n; j++)
377      {  GLPCOL *col = lp->col[j];
378         /* status, primal value, dual value */
379         fprintf(fp, "%d %.*g %.*g\n", col->stat, DBL_DIG, col->prim,
380            DBL_DIG, col->dual);
381      }
382      fflush(fp);
383      if (ferror(fp))
384      {  xprintf("Write error on `%s' - %s\n", fname, strerror(errno));
385         ret = 1;
386         goto done;
387      }
388      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
389done: if (fp != NULL) fclose(fp);
390      return ret;
391}
392
393/**********************************************************************/
394
395int glp_print_ipt(glp_prob *P, const char *fname)
396{     /* write interior-point solution in printable format */
397      XFILE *fp;
398      GLPROW *row;
399      GLPCOL *col;
400      int i, j, t, ae_ind, re_ind, ret;
401      double ae_max, re_max;
402      xprintf("Writing interior-point solution to `%s'...\n", fname);
403      fp = xfopen(fname, "w");
404      if (fp == NULL)
405      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
406         ret = 1;
407         goto done;
408      }
409      xfprintf(fp, "%-12s%s\n", "Problem:",
410         P->name == NULL ? "" : P->name);
411      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
412      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
413      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
414      t = glp_ipt_status(P);
415      xfprintf(fp, "%-12s%s\n", "Status:",
416         t == GLP_OPT    ? "OPTIMAL" :
417         t == GLP_UNDEF  ? "UNDEFINED" : "???");
418      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
419         P->obj == NULL ? "" : P->obj,
420         P->obj == NULL ? "" : " = ", P->ipt_obj,
421         P->dir == GLP_MIN ? "MINimum" :
422         P->dir == GLP_MAX ? "MAXimum" : "???");
423      xfprintf(fp, "\n");
424      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
425         " Upper bound    Marginal\n");
426      xfprintf(fp, "------ ------------    ------------- ------------- "
427         "------------- -------------\n");
428      for (i = 1; i <= P->m; i++)
429      {  row = P->row[i];
430         xfprintf(fp, "%6d ", i);
431         if (row->name == NULL || strlen(row->name) <= 12)
432            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
433         else
434            xfprintf(fp, "%s\n%20s", row->name, "");
435         xfprintf(fp, "%3s", "");
436         xfprintf(fp, "%13.6g ",
437            fabs(row->pval) <= 1e-9 ? 0.0 : row->pval);
438         if (row->type == GLP_LO || row->type == GLP_DB ||
439             row->type == GLP_FX)
440            xfprintf(fp, "%13.6g ", row->lb);
441         else
442            xfprintf(fp, "%13s ", "");
443         if (row->type == GLP_UP || row->type == GLP_DB)
444            xfprintf(fp, "%13.6g ", row->ub);
445         else
446            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
447         if (fabs(row->dval) <= 1e-9)
448            xfprintf(fp, "%13s", "< eps");
449         else
450            xfprintf(fp, "%13.6g ", row->dval);
451         xfprintf(fp, "\n");
452      }
453      xfprintf(fp, "\n");
454      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
455         " Upper bound    Marginal\n");
456      xfprintf(fp, "------ ------------    ------------- ------------- "
457         "------------- -------------\n");
458      for (j = 1; j <= P->n; j++)
459      {  col = P->col[j];
460         xfprintf(fp, "%6d ", j);
461         if (col->name == NULL || strlen(col->name) <= 12)
462            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
463         else
464            xfprintf(fp, "%s\n%20s", col->name, "");
465         xfprintf(fp, "%3s", "");
466         xfprintf(fp, "%13.6g ",
467            fabs(col->pval) <= 1e-9 ? 0.0 : col->pval);
468         if (col->type == GLP_LO || col->type == GLP_DB ||
469             col->type == GLP_FX)
470            xfprintf(fp, "%13.6g ", col->lb);
471         else
472            xfprintf(fp, "%13s ", "");
473         if (col->type == GLP_UP || col->type == GLP_DB)
474            xfprintf(fp, "%13.6g ", col->ub);
475         else
476            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
477         if (fabs(col->dval) <= 1e-9)
478            xfprintf(fp, "%13s", "< eps");
479         else
480            xfprintf(fp, "%13.6g ", col->dval);
481         xfprintf(fp, "\n");
482      }
483      xfprintf(fp, "\n");
484      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
485      xfprintf(fp, "\n");
486      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
487         &re_ind);
488      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
489         ae_max, ae_ind);
490      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
491         re_max, re_ind);
492      xfprintf(fp, "%8s%s\n", "",
493         re_max <= 1e-9 ? "High quality" :
494         re_max <= 1e-6 ? "Medium quality" :
495         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
496      xfprintf(fp, "\n");
497      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
498         &re_ind);
499      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
500            ae_max, ae_ind <= P->m ? "row" : "column",
501            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
502      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
503            re_max, re_ind <= P->m ? "row" : "column",
504            re_ind <= P->m ? re_ind : re_ind - P->m);
505      xfprintf(fp, "%8s%s\n", "",
506         re_max <= 1e-9 ? "High quality" :
507         re_max <= 1e-6 ? "Medium quality" :
508         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
509            "E");
510      xfprintf(fp, "\n");
511      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
512         &re_ind);
513      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
514         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
515      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
516         re_max, re_ind == 0 ? 0 : re_ind - P->m);
517      xfprintf(fp, "%8s%s\n", "",
518         re_max <= 1e-9 ? "High quality" :
519         re_max <= 1e-6 ? "Medium quality" :
520         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
521      xfprintf(fp, "\n");
522      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
523         &re_ind);
524      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
525            ae_max, ae_ind <= P->m ? "row" : "column",
526            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
527      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
528            re_max, re_ind <= P->m ? "row" : "column",
529            re_ind <= P->m ? re_ind : re_ind - P->m);
530      xfprintf(fp, "%8s%s\n", "",
531         re_max <= 1e-9 ? "High quality" :
532         re_max <= 1e-6 ? "Medium quality" :
533         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
534            ;
535      xfprintf(fp, "\n");
536      xfprintf(fp, "End of output\n");
537      xfflush(fp);
538      if (xferror(fp))
539      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
540         ret = 1;
541         goto done;
542      }
543      ret = 0;
544done: if (fp != NULL) xfclose(fp);
545      return ret;
546}
547
548/***********************************************************************
549*  NAME
550*
551*  glp_read_ipt - read interior-point solution from text file
552*
553*  SYNOPSIS
554*
555*  int glp_read_ipt(glp_prob *lp, const char *fname);
556*
557*  DESCRIPTION
558*
559*  The routine glp_read_ipt reads interior-point solution from a text
560*  file whose name is specified by the parameter fname into the problem
561*  object.
562*
563*  For the file format see description of the routine glp_write_ipt.
564*
565*  RETURNS
566*
567*  On success the routine returns zero, otherwise non-zero. */
568
569int glp_read_ipt(glp_prob *lp, const char *fname)
570{     PDS *pds;
571      jmp_buf jump;
572      int i, j, k, ret = 0;
573      xprintf("Reading interior-point solution from `%s'...\n", fname);
574      pds = pds_open_file(fname);
575      if (pds == NULL)
576      {  ret = 1;
577         goto done;
578      }
579      if (setjmp(jump))
580      {  ret = 1;
581         goto done;
582      }
583      pds_set_jump(pds, jump);
584      /* number of rows, number of columns */
585      k = pds_scan_int(pds);
586      if (k != lp->m)
587         pds_error(pds, "wrong number of rows\n");
588      k = pds_scan_int(pds);
589      if (k != lp->n)
590         pds_error(pds, "wrong number of columns\n");
591      /* solution status, objective value */
592      k = pds_scan_int(pds);
593      if (!(k == GLP_UNDEF || k == GLP_OPT))
594         pds_error(pds, "invalid solution status\n");
595      lp->ipt_stat = k;
596      lp->ipt_obj = pds_scan_num(pds);
597      /* rows (auxiliary variables) */
598      for (i = 1; i <= lp->m; i++)
599      {  GLPROW *row = lp->row[i];
600         /* primal value, dual value */
601         row->pval = pds_scan_num(pds);
602         row->dval = pds_scan_num(pds);
603      }
604      /* columns (structural variables) */
605      for (j = 1; j <= lp->n; j++)
606      {  GLPCOL *col = lp->col[j];
607         /* primal value, dual value */
608         col->pval = pds_scan_num(pds);
609         col->dval = pds_scan_num(pds);
610      }
611      xprintf("%d lines were read\n", _glp_sds_line(pds));
612done: if (ret) lp->ipt_stat = GLP_UNDEF;
613      if (pds != NULL) pds_close_file(pds);
614      return ret;
615}
616
617/***********************************************************************
618*  NAME
619*
620*  glp_write_ipt - write interior-point solution to text file
621*
622*  SYNOPSIS
623*
624*  int glp_write_ipt(glp_prob *lp, const char *fname);
625*
626*  DESCRIPTION
627*
628*  The routine glp_write_ipt writes the current interior-point solution
629*  to a text file whose name is specified by the parameter fname. This
630*  file can be read back with the routine glp_read_ipt.
631*
632*  RETURNS
633*
634*  On success the routine returns zero, otherwise non-zero.
635*
636*  FILE FORMAT
637*
638*  The file created by the routine glp_write_ipt is a plain text file,
639*  which contains the following information:
640*
641*     m n
642*     stat obj_val
643*     r_prim[1] r_dual[1]
644*     . . .
645*     r_prim[m] r_dual[m]
646*     c_prim[1] c_dual[1]
647*     . . .
648*     c_prim[n] c_dual[n]
649*
650*  where:
651*  m is the number of rows (auxiliary variables);
652*  n is the number of columns (structural variables);
653*  stat is the solution status (GLP_UNDEF = 1 or GLP_OPT = 5);
654*  obj_val is the objective value;
655*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
656*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
657*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
658*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
659
660int glp_write_ipt(glp_prob *lp, const char *fname)
661{     FILE *fp;
662      int i, j, ret = 0;
663      xprintf("Writing interior-point solution to `%s'...\n", fname);
664      fp = fopen(fname, "w");
665      if (fp == NULL)
666      {  xprintf("Unable to create `%s' - %s\n", fname,
667            strerror(errno));
668         ret = 1;
669         goto done;
670      }
671      /* number of rows, number of columns */
672      fprintf(fp, "%d %d\n", lp->m, lp->n);
673      /* solution status, objective value */
674      fprintf(fp, "%d %.*g\n", lp->ipt_stat, DBL_DIG, lp->ipt_obj);
675      /* rows (auxiliary variables) */
676      for (i = 1; i <= lp->m; i++)
677      {  GLPROW *row = lp->row[i];
678         /* primal value, dual value */
679         fprintf(fp, "%.*g %.*g\n", DBL_DIG, row->pval, DBL_DIG,
680            row->dval);
681      }
682      /* columns (structural variables) */
683      for (j = 1; j <= lp->n; j++)
684      {  GLPCOL *col = lp->col[j];
685         /* primal value, dual value */
686         fprintf(fp, "%.*g %.*g\n", DBL_DIG, col->pval, DBL_DIG,
687            col->dval);
688      }
689      fflush(fp);
690      if (ferror(fp))
691      {  xprintf("Write error on `%s' - %s\n", fname, strerror(errno));
692         ret = 1;
693         goto done;
694      }
695      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
696done: if (fp != NULL) fclose(fp);
697      return ret;
698}
699
700/**********************************************************************/
701
702int glp_print_mip(glp_prob *P, const char *fname)
703{     /* write MIP solution in printable format */
704      XFILE *fp;
705      GLPROW *row;
706      GLPCOL *col;
707      int i, j, t, ae_ind, re_ind, ret;
708      double ae_max, re_max;
709      xprintf("Writing MIP solution to `%s'...\n", fname);
710      fp = xfopen(fname, "w");
711      if (fp == NULL)
712      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
713         ret = 1;
714         goto done;
715      }
716      xfprintf(fp, "%-12s%s\n", "Problem:",
717         P->name == NULL ? "" : P->name);
718      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
719      xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:",
720         P->n, glp_get_num_int(P), glp_get_num_bin(P));
721      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
722      t = glp_mip_status(P);
723      xfprintf(fp, "%-12s%s\n", "Status:",
724         t == GLP_OPT    ? "INTEGER OPTIMAL" :
725         t == GLP_FEAS   ? "INTEGER NON-OPTIMAL" :
726         t == GLP_NOFEAS ? "INTEGER EMPTY" :
727         t == GLP_UNDEF  ? "INTEGER UNDEFINED" : "???");
728      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
729         P->obj == NULL ? "" : P->obj,
730         P->obj == NULL ? "" : " = ", P->mip_obj,
731         P->dir == GLP_MIN ? "MINimum" :
732         P->dir == GLP_MAX ? "MAXimum" : "???");
733      xfprintf(fp, "\n");
734      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
735         " Upper bound\n");
736      xfprintf(fp, "------ ------------    ------------- ------------- "
737         "-------------\n");
738      for (i = 1; i <= P->m; i++)
739      {  row = P->row[i];
740         xfprintf(fp, "%6d ", i);
741         if (row->name == NULL || strlen(row->name) <= 12)
742            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
743         else
744            xfprintf(fp, "%s\n%20s", row->name, "");
745         xfprintf(fp, "%3s", "");
746         xfprintf(fp, "%13.6g ",
747            fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx);
748         if (row->type == GLP_LO || row->type == GLP_DB ||
749             row->type == GLP_FX)
750            xfprintf(fp, "%13.6g ", row->lb);
751         else
752            xfprintf(fp, "%13s ", "");
753         if (row->type == GLP_UP || row->type == GLP_DB)
754            xfprintf(fp, "%13.6g ", row->ub);
755         else
756            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
757         xfprintf(fp, "\n");
758      }
759      xfprintf(fp, "\n");
760      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
761         " Upper bound\n");
762      xfprintf(fp, "------ ------------    ------------- ------------- "
763         "-------------\n");
764      for (j = 1; j <= P->n; j++)
765      {  col = P->col[j];
766         xfprintf(fp, "%6d ", j);
767         if (col->name == NULL || strlen(col->name) <= 12)
768            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
769         else
770            xfprintf(fp, "%s\n%20s", col->name, "");
771         xfprintf(fp, "%s  ",
772            col->kind == GLP_CV ? " " :
773            col->kind == GLP_IV ? "*" : "?");
774         xfprintf(fp, "%13.6g ",
775            fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx);
776         if (col->type == GLP_LO || col->type == GLP_DB ||
777             col->type == GLP_FX)
778            xfprintf(fp, "%13.6g ", col->lb);
779         else
780            xfprintf(fp, "%13s ", "");
781         if (col->type == GLP_UP || col->type == GLP_DB)
782            xfprintf(fp, "%13.6g ", col->ub);
783         else
784            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
785         xfprintf(fp, "\n");
786      }
787      xfprintf(fp, "\n");
788      xfprintf(fp, "Integer feasibility conditions:\n");
789      xfprintf(fp, "\n");
790      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
791         &re_ind);
792      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
793         ae_max, ae_ind);
794      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
795         re_max, re_ind);
796      xfprintf(fp, "%8s%s\n", "",
797         re_max <= 1e-9 ? "High quality" :
798         re_max <= 1e-6 ? "Medium quality" :
799         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG");
800      xfprintf(fp, "\n");
801      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
802         &re_ind);
803      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
804            ae_max, ae_ind <= P->m ? "row" : "column",
805            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
806      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
807            re_max, re_ind <= P->m ? "row" : "column",
808            re_ind <= P->m ? re_ind : re_ind - P->m);
809      xfprintf(fp, "%8s%s\n", "",
810         re_max <= 1e-9 ? "High quality" :
811         re_max <= 1e-6 ? "Medium quality" :
812         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE");
813      xfprintf(fp, "\n");
814      xfprintf(fp, "End of output\n");
815      xfflush(fp);
816      if (xferror(fp))
817      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
818         ret = 1;
819         goto done;
820      }
821      ret = 0;
822done: if (fp != NULL) xfclose(fp);
823      return ret;
824}
825
826/***********************************************************************
827*  NAME
828*
829*  glp_read_mip - read MIP solution from text file
830*
831*  SYNOPSIS
832*
833*  int glp_read_mip(glp_prob *mip, const char *fname);
834*
835*  DESCRIPTION
836*
837*  The routine glp_read_mip reads MIP solution from a text file whose
838*  name is specified by the parameter fname into the problem object.
839*
840*  For the file format see description of the routine glp_write_mip.
841*
842*  RETURNS
843*
844*  On success the routine returns zero, otherwise non-zero. */
845
846int glp_read_mip(glp_prob *mip, const char *fname)
847{     PDS *pds;
848      jmp_buf jump;
849      int i, j, k, ret = 0;
850      xprintf("Reading MIP solution from `%s'...\n", fname);
851      pds = pds_open_file(fname);
852      if (pds == NULL)
853      {  ret = 1;
854         goto done;
855      }
856      if (setjmp(jump))
857      {  ret = 1;
858         goto done;
859      }
860      pds_set_jump(pds, jump);
861      /* number of rows, number of columns */
862      k = pds_scan_int(pds);
863      if (k != mip->m)
864         pds_error(pds, "wrong number of rows\n");
865      k = pds_scan_int(pds);
866      if (k != mip->n)
867         pds_error(pds, "wrong number of columns\n");
868      /* solution status, objective value */
869      k = pds_scan_int(pds);
870      if (!(k == GLP_UNDEF || k == GLP_OPT || k == GLP_FEAS ||
871            k == GLP_NOFEAS))
872         pds_error(pds, "invalid solution status\n");
873      mip->mip_stat = k;
874      mip->mip_obj = pds_scan_num(pds);
875      /* rows (auxiliary variables) */
876      for (i = 1; i <= mip->m; i++)
877      {  GLPROW *row = mip->row[i];
878         row->mipx = pds_scan_num(pds);
879      }
880      /* columns (structural variables) */
881      for (j = 1; j <= mip->n; j++)
882      {  GLPCOL *col = mip->col[j];
883         col->mipx = pds_scan_num(pds);
884         if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
885            pds_error(pds, "non-integer column value");
886      }
887      xprintf("%d lines were read\n", _glp_sds_line(pds));
888done: if (ret) mip->mip_stat = GLP_UNDEF;
889      if (pds != NULL) pds_close_file(pds);
890      return ret;
891}
892
893/***********************************************************************
894*  NAME
895*
896*  glp_write_mip - write MIP solution to text file
897*
898*  SYNOPSIS
899*
900*  int glp_write_mip(glp_prob *mip, const char *fname);
901*
902*  DESCRIPTION
903*
904*  The routine glp_write_mip writes the current MIP solution to a text
905*  file whose name is specified by the parameter fname. This file can
906*  be read back with the routine glp_read_mip.
907*
908*  RETURNS
909*
910*  On success the routine returns zero, otherwise non-zero.
911*
912*  FILE FORMAT
913*
914*  The file created by the routine glp_write_sol is a plain text file,
915*  which contains the following information:
916*
917*     m n
918*     stat obj_val
919*     r_val[1]
920*     . . .
921*     r_val[m]
922*     c_val[1]
923*     . . .
924*     c_val[n]
925*
926*  where:
927*  m is the number of rows (auxiliary variables);
928*  n is the number of columns (structural variables);
929*  stat is the solution status (GLP_UNDEF = 1, GLP_FEAS = 2,
930*     GLP_NOFEAS = 4, or GLP_OPT = 5);
931*  obj_val is the objective value;
932*  r_val[i], i = 1,...,m, is the value of i-th row;
933*  c_val[j], j = 1,...,n, is the value of j-th column. */
934
935int glp_write_mip(glp_prob *mip, const char *fname)
936{     FILE *fp;
937      int i, j, ret = 0;
938      xprintf("Writing MIP solution to `%s'...\n", fname);
939      fp = fopen(fname, "w");
940      if (fp == NULL)
941      {  xprintf("Unable to create `%s' - %s\n", fname,
942            strerror(errno));
943         ret = 1;
944         goto done;
945      }
946      /* number of rows, number of columns */
947      fprintf(fp, "%d %d\n", mip->m, mip->n);
948      /* solution status, objective value */
949      fprintf(fp, "%d %.*g\n", mip->mip_stat, DBL_DIG, mip->mip_obj);
950      /* rows (auxiliary variables) */
951      for (i = 1; i <= mip->m; i++)
952         fprintf(fp, "%.*g\n", DBL_DIG, mip->row[i]->mipx);
953      /* columns (structural variables) */
954      for (j = 1; j <= mip->n; j++)
955         fprintf(fp, "%.*g\n", DBL_DIG, mip->col[j]->mipx);
956      fflush(fp);
957      if (ferror(fp))
958      {  xprintf("Write error on `%s' - %s\n", fname, strerror(errno));
959         ret = 1;
960         goto done;
961      }
962      xprintf("%d lines were written\n", 2 + mip->m + mip->n);
963done: if (fp != NULL) fclose(fp);
964      return ret;
965}
966
967/* eof */