lemon-project-template-glpk

annotate deps/glpk/src/glpios10.c @ 11:4fc6ad2fb8a6

Test GLPK in src/main.cc
author Alpar Juttner <alpar@cs.elte.hu>
date Sun, 06 Nov 2011 21:43:29 +0100
parents
children
rev   line source
alpar@9 1 /* glpios10.c (feasibility pump heuristic) */
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 "glpios.h"
alpar@9 26 #include "glprng.h"
alpar@9 27
alpar@9 28 /***********************************************************************
alpar@9 29 * NAME
alpar@9 30 *
alpar@9 31 * ios_feas_pump - feasibility pump heuristic
alpar@9 32 *
alpar@9 33 * SYNOPSIS
alpar@9 34 *
alpar@9 35 * #include "glpios.h"
alpar@9 36 * void ios_feas_pump(glp_tree *T);
alpar@9 37 *
alpar@9 38 * DESCRIPTION
alpar@9 39 *
alpar@9 40 * The routine ios_feas_pump is a simple implementation of the Feasi-
alpar@9 41 * bility Pump heuristic.
alpar@9 42 *
alpar@9 43 * REFERENCES
alpar@9 44 *
alpar@9 45 * M.Fischetti, F.Glover, and A.Lodi. "The feasibility pump." Math.
alpar@9 46 * Program., Ser. A 104, pp. 91-104 (2005). */
alpar@9 47
alpar@9 48 struct VAR
alpar@9 49 { /* binary variable */
alpar@9 50 int j;
alpar@9 51 /* ordinal number */
alpar@9 52 int x;
alpar@9 53 /* value in the rounded solution (0 or 1) */
alpar@9 54 double d;
alpar@9 55 /* sorting key */
alpar@9 56 };
alpar@9 57
alpar@9 58 static int fcmp(const void *x, const void *y)
alpar@9 59 { /* comparison routine */
alpar@9 60 const struct VAR *vx = x, *vy = y;
alpar@9 61 if (vx->d > vy->d)
alpar@9 62 return -1;
alpar@9 63 else if (vx->d < vy->d)
alpar@9 64 return +1;
alpar@9 65 else
alpar@9 66 return 0;
alpar@9 67 }
alpar@9 68
alpar@9 69 void ios_feas_pump(glp_tree *T)
alpar@9 70 { glp_prob *P = T->mip;
alpar@9 71 int n = P->n;
alpar@9 72 glp_prob *lp = NULL;
alpar@9 73 struct VAR *var = NULL;
alpar@9 74 RNG *rand = NULL;
alpar@9 75 GLPCOL *col;
alpar@9 76 glp_smcp parm;
alpar@9 77 int j, k, new_x, nfail, npass, nv, ret, stalling;
alpar@9 78 double dist, tol;
alpar@9 79 xassert(glp_get_status(P) == GLP_OPT);
alpar@9 80 /* this heuristic is applied only once on the root level */
alpar@9 81 if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done;
alpar@9 82 /* determine number of binary variables */
alpar@9 83 nv = 0;
alpar@9 84 for (j = 1; j <= n; j++)
alpar@9 85 { col = P->col[j];
alpar@9 86 /* if x[j] is continuous, skip it */
alpar@9 87 if (col->kind == GLP_CV) continue;
alpar@9 88 /* if x[j] is fixed, skip it */
alpar@9 89 if (col->type == GLP_FX) continue;
alpar@9 90 /* x[j] is non-fixed integer */
alpar@9 91 xassert(col->kind == GLP_IV);
alpar@9 92 if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
alpar@9 93 { /* x[j] is binary */
alpar@9 94 nv++;
alpar@9 95 }
alpar@9 96 else
alpar@9 97 { /* x[j] is general integer */
alpar@9 98 if (T->parm->msg_lev >= GLP_MSG_ALL)
alpar@9 99 xprintf("FPUMP heuristic cannot be applied due to genera"
alpar@9 100 "l integer variables\n");
alpar@9 101 goto done;
alpar@9 102 }
alpar@9 103 }
alpar@9 104 /* there must be at least one binary variable */
alpar@9 105 if (nv == 0) goto done;
alpar@9 106 if (T->parm->msg_lev >= GLP_MSG_ALL)
alpar@9 107 xprintf("Applying FPUMP heuristic...\n");
alpar@9 108 /* build the list of binary variables */
alpar@9 109 var = xcalloc(1+nv, sizeof(struct VAR));
alpar@9 110 k = 0;
alpar@9 111 for (j = 1; j <= n; j++)
alpar@9 112 { col = P->col[j];
alpar@9 113 if (col->kind == GLP_IV && col->type == GLP_DB)
alpar@9 114 var[++k].j = j;
alpar@9 115 }
alpar@9 116 xassert(k == nv);
alpar@9 117 /* create working problem object */
alpar@9 118 lp = glp_create_prob();
alpar@9 119 more: /* copy the original problem object to keep it intact */
alpar@9 120 glp_copy_prob(lp, P, GLP_OFF);
alpar@9 121 /* we are interested to find an integer feasible solution, which
alpar@9 122 is better than the best known one */
alpar@9 123 if (P->mip_stat == GLP_FEAS)
alpar@9 124 { int *ind;
alpar@9 125 double *val, bnd;
alpar@9 126 /* add a row and make it identical to the objective row */
alpar@9 127 glp_add_rows(lp, 1);
alpar@9 128 ind = xcalloc(1+n, sizeof(int));
alpar@9 129 val = xcalloc(1+n, sizeof(double));
alpar@9 130 for (j = 1; j <= n; j++)
alpar@9 131 { ind[j] = j;
alpar@9 132 val[j] = P->col[j]->coef;
alpar@9 133 }
alpar@9 134 glp_set_mat_row(lp, lp->m, n, ind, val);
alpar@9 135 xfree(ind);
alpar@9 136 xfree(val);
alpar@9 137 /* introduce upper (minimization) or lower (maximization)
alpar@9 138 bound to the original objective function; note that this
alpar@9 139 additional constraint is not violated at the optimal point
alpar@9 140 to LP relaxation */
alpar@9 141 #if 0 /* modified by xypron <xypron.glpk@gmx.de> */
alpar@9 142 if (P->dir == GLP_MIN)
alpar@9 143 { bnd = P->mip_obj - 0.10 * (1.0 + fabs(P->mip_obj));
alpar@9 144 if (bnd < P->obj_val) bnd = P->obj_val;
alpar@9 145 glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
alpar@9 146 }
alpar@9 147 else if (P->dir == GLP_MAX)
alpar@9 148 { bnd = P->mip_obj + 0.10 * (1.0 + fabs(P->mip_obj));
alpar@9 149 if (bnd > P->obj_val) bnd = P->obj_val;
alpar@9 150 glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
alpar@9 151 }
alpar@9 152 else
alpar@9 153 xassert(P != P);
alpar@9 154 #else
alpar@9 155 bnd = 0.1 * P->obj_val + 0.9 * P->mip_obj;
alpar@9 156 /* xprintf("bnd = %f\n", bnd); */
alpar@9 157 if (P->dir == GLP_MIN)
alpar@9 158 glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
alpar@9 159 else if (P->dir == GLP_MAX)
alpar@9 160 glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
alpar@9 161 else
alpar@9 162 xassert(P != P);
alpar@9 163 #endif
alpar@9 164 }
alpar@9 165 /* reset pass count */
alpar@9 166 npass = 0;
alpar@9 167 /* invalidate the rounded point */
alpar@9 168 for (k = 1; k <= nv; k++)
alpar@9 169 var[k].x = -1;
alpar@9 170 pass: /* next pass starts here */
alpar@9 171 npass++;
alpar@9 172 if (T->parm->msg_lev >= GLP_MSG_ALL)
alpar@9 173 xprintf("Pass %d\n", npass);
alpar@9 174 /* initialize minimal distance between the basic point and the
alpar@9 175 rounded one obtained during this pass */
alpar@9 176 dist = DBL_MAX;
alpar@9 177 /* reset failure count (the number of succeeded iterations failed
alpar@9 178 to improve the distance) */
alpar@9 179 nfail = 0;
alpar@9 180 /* if it is not the first pass, perturb the last rounded point
alpar@9 181 rather than construct it from the basic solution */
alpar@9 182 if (npass > 1)
alpar@9 183 { double rho, temp;
alpar@9 184 if (rand == NULL)
alpar@9 185 rand = rng_create_rand();
alpar@9 186 for (k = 1; k <= nv; k++)
alpar@9 187 { j = var[k].j;
alpar@9 188 col = lp->col[j];
alpar@9 189 rho = rng_uniform(rand, -0.3, 0.7);
alpar@9 190 if (rho < 0.0) rho = 0.0;
alpar@9 191 temp = fabs((double)var[k].x - col->prim);
alpar@9 192 if (temp + rho > 0.5) var[k].x = 1 - var[k].x;
alpar@9 193 }
alpar@9 194 goto skip;
alpar@9 195 }
alpar@9 196 loop: /* innermost loop begins here */
alpar@9 197 /* round basic solution (which is assumed primal feasible) */
alpar@9 198 stalling = 1;
alpar@9 199 for (k = 1; k <= nv; k++)
alpar@9 200 { col = lp->col[var[k].j];
alpar@9 201 if (col->prim < 0.5)
alpar@9 202 { /* rounded value is 0 */
alpar@9 203 new_x = 0;
alpar@9 204 }
alpar@9 205 else
alpar@9 206 { /* rounded value is 1 */
alpar@9 207 new_x = 1;
alpar@9 208 }
alpar@9 209 if (var[k].x != new_x)
alpar@9 210 { stalling = 0;
alpar@9 211 var[k].x = new_x;
alpar@9 212 }
alpar@9 213 }
alpar@9 214 /* if the rounded point has not changed (stalling), choose and
alpar@9 215 flip some its entries heuristically */
alpar@9 216 if (stalling)
alpar@9 217 { /* compute d[j] = |x[j] - round(x[j])| */
alpar@9 218 for (k = 1; k <= nv; k++)
alpar@9 219 { col = lp->col[var[k].j];
alpar@9 220 var[k].d = fabs(col->prim - (double)var[k].x);
alpar@9 221 }
alpar@9 222 /* sort the list of binary variables by descending d[j] */
alpar@9 223 qsort(&var[1], nv, sizeof(struct VAR), fcmp);
alpar@9 224 /* choose and flip some rounded components */
alpar@9 225 for (k = 1; k <= nv; k++)
alpar@9 226 { if (k >= 5 && var[k].d < 0.35 || k >= 10) break;
alpar@9 227 var[k].x = 1 - var[k].x;
alpar@9 228 }
alpar@9 229 }
alpar@9 230 skip: /* check if the time limit has been exhausted */
alpar@9 231 if (T->parm->tm_lim < INT_MAX &&
alpar@9 232 (double)(T->parm->tm_lim - 1) <=
alpar@9 233 1000.0 * xdifftime(xtime(), T->tm_beg)) goto done;
alpar@9 234 /* build the objective, which is the distance between the current
alpar@9 235 (basic) point and the rounded one */
alpar@9 236 lp->dir = GLP_MIN;
alpar@9 237 lp->c0 = 0.0;
alpar@9 238 for (j = 1; j <= n; j++)
alpar@9 239 lp->col[j]->coef = 0.0;
alpar@9 240 for (k = 1; k <= nv; k++)
alpar@9 241 { j = var[k].j;
alpar@9 242 if (var[k].x == 0)
alpar@9 243 lp->col[j]->coef = +1.0;
alpar@9 244 else
alpar@9 245 { lp->col[j]->coef = -1.0;
alpar@9 246 lp->c0 += 1.0;
alpar@9 247 }
alpar@9 248 }
alpar@9 249 /* minimize the distance with the simplex method */
alpar@9 250 glp_init_smcp(&parm);
alpar@9 251 if (T->parm->msg_lev <= GLP_MSG_ERR)
alpar@9 252 parm.msg_lev = T->parm->msg_lev;
alpar@9 253 else if (T->parm->msg_lev <= GLP_MSG_ALL)
alpar@9 254 { parm.msg_lev = GLP_MSG_ON;
alpar@9 255 parm.out_dly = 10000;
alpar@9 256 }
alpar@9 257 ret = glp_simplex(lp, &parm);
alpar@9 258 if (ret != 0)
alpar@9 259 { if (T->parm->msg_lev >= GLP_MSG_ERR)
alpar@9 260 xprintf("Warning: glp_simplex returned %d\n", ret);
alpar@9 261 goto done;
alpar@9 262 }
alpar@9 263 ret = glp_get_status(lp);
alpar@9 264 if (ret != GLP_OPT)
alpar@9 265 { if (T->parm->msg_lev >= GLP_MSG_ERR)
alpar@9 266 xprintf("Warning: glp_get_status returned %d\n", ret);
alpar@9 267 goto done;
alpar@9 268 }
alpar@9 269 if (T->parm->msg_lev >= GLP_MSG_DBG)
alpar@9 270 xprintf("delta = %g\n", lp->obj_val);
alpar@9 271 /* check if the basic solution is integer feasible; note that it
alpar@9 272 may be so even if the minimial distance is positive */
alpar@9 273 tol = 0.3 * T->parm->tol_int;
alpar@9 274 for (k = 1; k <= nv; k++)
alpar@9 275 { col = lp->col[var[k].j];
alpar@9 276 if (tol < col->prim && col->prim < 1.0 - tol) break;
alpar@9 277 }
alpar@9 278 if (k > nv)
alpar@9 279 { /* okay; the basic solution seems to be integer feasible */
alpar@9 280 double *x = xcalloc(1+n, sizeof(double));
alpar@9 281 for (j = 1; j <= n; j++)
alpar@9 282 { x[j] = lp->col[j]->prim;
alpar@9 283 if (P->col[j]->kind == GLP_IV) x[j] = floor(x[j] + 0.5);
alpar@9 284 }
alpar@9 285 #if 1 /* modified by xypron <xypron.glpk@gmx.de> */
alpar@9 286 /* reset direction and right-hand side of objective */
alpar@9 287 lp->c0 = P->c0;
alpar@9 288 lp->dir = P->dir;
alpar@9 289 /* fix integer variables */
alpar@9 290 for (k = 1; k <= nv; k++)
alpar@9 291 { lp->col[var[k].j]->lb = x[var[k].j];
alpar@9 292 lp->col[var[k].j]->ub = x[var[k].j];
alpar@9 293 lp->col[var[k].j]->type = GLP_FX;
alpar@9 294 }
alpar@9 295 /* copy original objective function */
alpar@9 296 for (j = 1; j <= n; j++)
alpar@9 297 lp->col[j]->coef = P->col[j]->coef;
alpar@9 298 /* solve original LP and copy result */
alpar@9 299 ret = glp_simplex(lp, &parm);
alpar@9 300 if (ret != 0)
alpar@9 301 { if (T->parm->msg_lev >= GLP_MSG_ERR)
alpar@9 302 xprintf("Warning: glp_simplex returned %d\n", ret);
alpar@9 303 goto done;
alpar@9 304 }
alpar@9 305 ret = glp_get_status(lp);
alpar@9 306 if (ret != GLP_OPT)
alpar@9 307 { if (T->parm->msg_lev >= GLP_MSG_ERR)
alpar@9 308 xprintf("Warning: glp_get_status returned %d\n", ret);
alpar@9 309 goto done;
alpar@9 310 }
alpar@9 311 for (j = 1; j <= n; j++)
alpar@9 312 if (P->col[j]->kind != GLP_IV) x[j] = lp->col[j]->prim;
alpar@9 313 #endif
alpar@9 314 ret = glp_ios_heur_sol(T, x);
alpar@9 315 xfree(x);
alpar@9 316 if (ret == 0)
alpar@9 317 { /* the integer solution is accepted */
alpar@9 318 if (ios_is_hopeful(T, T->curr->bound))
alpar@9 319 { /* it is reasonable to apply the heuristic once again */
alpar@9 320 goto more;
alpar@9 321 }
alpar@9 322 else
alpar@9 323 { /* the best known integer feasible solution just found
alpar@9 324 is close to optimal solution to LP relaxation */
alpar@9 325 goto done;
alpar@9 326 }
alpar@9 327 }
alpar@9 328 }
alpar@9 329 /* the basic solution is fractional */
alpar@9 330 if (dist == DBL_MAX ||
alpar@9 331 lp->obj_val <= dist - 1e-6 * (1.0 + dist))
alpar@9 332 { /* the distance is reducing */
alpar@9 333 nfail = 0, dist = lp->obj_val;
alpar@9 334 }
alpar@9 335 else
alpar@9 336 { /* improving the distance failed */
alpar@9 337 nfail++;
alpar@9 338 }
alpar@9 339 if (nfail < 3) goto loop;
alpar@9 340 if (npass < 5) goto pass;
alpar@9 341 done: /* delete working objects */
alpar@9 342 if (lp != NULL) glp_delete_prob(lp);
alpar@9 343 if (var != NULL) xfree(var);
alpar@9 344 if (rand != NULL) rng_delete_rand(rand);
alpar@9 345 return;
alpar@9 346 }
alpar@9 347
alpar@9 348 /* eof */