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