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