lemon-project-template-glpk

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

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