src/glpios09.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
/* glpios09.c (branching heuristics) */
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 "glpios.h"
alpar@1
    26
alpar@1
    27
/***********************************************************************
alpar@1
    28
*  NAME
alpar@1
    29
*
alpar@1
    30
*  ios_choose_var - select variable to branch on
alpar@1
    31
*
alpar@1
    32
*  SYNOPSIS
alpar@1
    33
*
alpar@1
    34
*  #include "glpios.h"
alpar@1
    35
*  int ios_choose_var(glp_tree *T, int *next);
alpar@1
    36
*
alpar@1
    37
*  The routine ios_choose_var chooses a variable from the candidate
alpar@1
    38
*  list to branch on. Additionally the routine provides a flag stored
alpar@1
    39
*  in the location next to suggests which of the child subproblems
alpar@1
    40
*  should be solved next.
alpar@1
    41
*
alpar@1
    42
*  RETURNS
alpar@1
    43
*
alpar@1
    44
*  The routine ios_choose_var returns the ordinal number of the column
alpar@1
    45
*  choosen. */
alpar@1
    46
alpar@1
    47
static int branch_first(glp_tree *T, int *next);
alpar@1
    48
static int branch_last(glp_tree *T, int *next);
alpar@1
    49
static int branch_mostf(glp_tree *T, int *next);
alpar@1
    50
static int branch_drtom(glp_tree *T, int *next);
alpar@1
    51
alpar@1
    52
int ios_choose_var(glp_tree *T, int *next)
alpar@1
    53
{     int j;
alpar@1
    54
      if (T->parm->br_tech == GLP_BR_FFV)
alpar@1
    55
      {  /* branch on first fractional variable */
alpar@1
    56
         j = branch_first(T, next);
alpar@1
    57
      }
alpar@1
    58
      else if (T->parm->br_tech == GLP_BR_LFV)
alpar@1
    59
      {  /* branch on last fractional variable */
alpar@1
    60
         j = branch_last(T, next);
alpar@1
    61
      }
alpar@1
    62
      else if (T->parm->br_tech == GLP_BR_MFV)
alpar@1
    63
      {  /* branch on most fractional variable */
alpar@1
    64
         j = branch_mostf(T, next);
alpar@1
    65
      }
alpar@1
    66
      else if (T->parm->br_tech == GLP_BR_DTH)
alpar@1
    67
      {  /* branch using the heuristic by Dreebeck and Tomlin */
alpar@1
    68
         j = branch_drtom(T, next);
alpar@1
    69
      }
alpar@1
    70
      else if (T->parm->br_tech == GLP_BR_PCH)
alpar@1
    71
      {  /* hybrid pseudocost heuristic */
alpar@1
    72
         j = ios_pcost_branch(T, next);
alpar@1
    73
      }
alpar@1
    74
      else
alpar@1
    75
         xassert(T != T);
alpar@1
    76
      return j;
alpar@1
    77
}
alpar@1
    78
alpar@1
    79
/***********************************************************************
alpar@1
    80
*  branch_first - choose first branching variable
alpar@1
    81
*
alpar@1
    82
*  This routine looks up the list of structural variables and chooses
alpar@1
    83
*  the first one, which is of integer kind and has fractional value in
alpar@1
    84
*  optimal solution to the current LP relaxation.
alpar@1
    85
*
alpar@1
    86
*  This routine also selects the branch to be solved next where integer
alpar@1
    87
*  infeasibility of the chosen variable is less than in other one. */
alpar@1
    88
alpar@1
    89
static int branch_first(glp_tree *T, int *_next)
alpar@1
    90
{     int j, next;
alpar@1
    91
      double beta;
alpar@1
    92
      /* choose the column to branch on */
alpar@1
    93
      for (j = 1; j <= T->n; j++)
alpar@1
    94
         if (T->non_int[j]) break;
alpar@1
    95
      xassert(1 <= j && j <= T->n);
alpar@1
    96
      /* select the branch to be solved next */
alpar@1
    97
      beta = glp_get_col_prim(T->mip, j);
alpar@1
    98
      if (beta - floor(beta) < ceil(beta) - beta)
alpar@1
    99
         next = GLP_DN_BRNCH;
alpar@1
   100
      else
alpar@1
   101
         next = GLP_UP_BRNCH;
alpar@1
   102
      *_next = next;
alpar@1
   103
      return j;
alpar@1
   104
}
alpar@1
   105
alpar@1
   106
/***********************************************************************
alpar@1
   107
*  branch_last - choose last branching variable
alpar@1
   108
*
alpar@1
   109
*  This routine looks up the list of structural variables and chooses
alpar@1
   110
*  the last one, which is of integer kind and has fractional value in
alpar@1
   111
*  optimal solution to the current LP relaxation.
alpar@1
   112
*
alpar@1
   113
*  This routine also selects the branch to be solved next where integer
alpar@1
   114
*  infeasibility of the chosen variable is less than in other one. */
alpar@1
   115
alpar@1
   116
static int branch_last(glp_tree *T, int *_next)
alpar@1
   117
{     int j, next;
alpar@1
   118
      double beta;
alpar@1
   119
      /* choose the column to branch on */
alpar@1
   120
      for (j = T->n; j >= 1; j--)
alpar@1
   121
         if (T->non_int[j]) break;
alpar@1
   122
      xassert(1 <= j && j <= T->n);
alpar@1
   123
      /* select the branch to be solved next */
alpar@1
   124
      beta = glp_get_col_prim(T->mip, j);
alpar@1
   125
      if (beta - floor(beta) < ceil(beta) - beta)
alpar@1
   126
         next = GLP_DN_BRNCH;
alpar@1
   127
      else
alpar@1
   128
         next = GLP_UP_BRNCH;
alpar@1
   129
      *_next = next;
alpar@1
   130
      return j;
alpar@1
   131
}
alpar@1
   132
alpar@1
   133
/***********************************************************************
alpar@1
   134
*  branch_mostf - choose most fractional branching variable
alpar@1
   135
*
alpar@1
   136
*  This routine looks up the list of structural variables and chooses
alpar@1
   137
*  that one, which is of integer kind and has most fractional value in
alpar@1
   138
*  optimal solution to the current LP relaxation.
alpar@1
   139
*
alpar@1
   140
*  This routine also selects the branch to be solved next where integer
alpar@1
   141
*  infeasibility of the chosen variable is less than in other one.
alpar@1
   142
*
alpar@1
   143
*  (Alexander Martin notices that "...most infeasible is as good as
alpar@1
   144
*  random...".) */
alpar@1
   145
alpar@1
   146
static int branch_mostf(glp_tree *T, int *_next)
alpar@1
   147
{     int j, jj, next;
alpar@1
   148
      double beta, most, temp;
alpar@1
   149
      /* choose the column to branch on */
alpar@1
   150
      jj = 0, most = DBL_MAX;
alpar@1
   151
      for (j = 1; j <= T->n; j++)
alpar@1
   152
      {  if (T->non_int[j])
alpar@1
   153
         {  beta = glp_get_col_prim(T->mip, j);
alpar@1
   154
            temp = floor(beta) + 0.5;
alpar@1
   155
            if (most > fabs(beta - temp))
alpar@1
   156
            {  jj = j, most = fabs(beta - temp);
alpar@1
   157
               if (beta < temp)
alpar@1
   158
                  next = GLP_DN_BRNCH;
alpar@1
   159
               else
alpar@1
   160
                  next = GLP_UP_BRNCH;
alpar@1
   161
            }
alpar@1
   162
         }
alpar@1
   163
      }
alpar@1
   164
      *_next = next;
alpar@1
   165
      return jj;
alpar@1
   166
}
alpar@1
   167
alpar@1
   168
/***********************************************************************
alpar@1
   169
*  branch_drtom - choose branching var using Driebeck-Tomlin heuristic
alpar@1
   170
*
alpar@1
   171
*  This routine chooses a structural variable, which is required to be
alpar@1
   172
*  integral and has fractional value in optimal solution of the current
alpar@1
   173
*  LP relaxation, using a heuristic proposed by Driebeck and Tomlin.
alpar@1
   174
*
alpar@1
   175
*  The routine also selects the branch to be solved next, again due to
alpar@1
   176
*  Driebeck and Tomlin.
alpar@1
   177
*
alpar@1
   178
*  This routine is based on the heuristic proposed in:
alpar@1
   179
*
alpar@1
   180
*  Driebeck N.J. An algorithm for the solution of mixed-integer
alpar@1
   181
*  programming problems, Management Science, 12: 576-87 (1966);
alpar@1
   182
*
alpar@1
   183
*  and improved in:
alpar@1
   184
*
alpar@1
   185
*  Tomlin J.A. Branch and bound methods for integer and non-convex
alpar@1
   186
*  programming, in J.Abadie (ed.), Integer and Nonlinear Programming,
alpar@1
   187
*  North-Holland, Amsterdam, pp. 437-50 (1970).
alpar@1
   188
*
alpar@1
   189
*  Must note that this heuristic is time-expensive, because computing
alpar@1
   190
*  one-step degradation (see the routine below) requires one BTRAN for
alpar@1
   191
*  each fractional-valued structural variable. */
alpar@1
   192
alpar@1
   193
static int branch_drtom(glp_tree *T, int *_next)
alpar@1
   194
{     glp_prob *mip = T->mip;
alpar@1
   195
      int m = mip->m;
alpar@1
   196
      int n = mip->n;
alpar@1
   197
      char *non_int = T->non_int;
alpar@1
   198
      int j, jj, k, t, next, kase, len, stat, *ind;
alpar@1
   199
      double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up,
alpar@1
   200
         dd_dn, dd_up, degrad, *val;
alpar@1
   201
      /* basic solution of LP relaxation must be optimal */
alpar@1
   202
      xassert(glp_get_status(mip) == GLP_OPT);
alpar@1
   203
      /* allocate working arrays */
alpar@1
   204
      ind = xcalloc(1+n, sizeof(int));
alpar@1
   205
      val = xcalloc(1+n, sizeof(double));
alpar@1
   206
      /* nothing has been chosen so far */
alpar@1
   207
      jj = 0, degrad = -1.0;
alpar@1
   208
      /* walk through the list of columns (structural variables) */
alpar@1
   209
      for (j = 1; j <= n; j++)
alpar@1
   210
      {  /* if j-th column is not marked as fractional, skip it */
alpar@1
   211
         if (!non_int[j]) continue;
alpar@1
   212
         /* obtain (fractional) value of j-th column in basic solution
alpar@1
   213
            of LP relaxation */
alpar@1
   214
         x = glp_get_col_prim(mip, j);
alpar@1
   215
         /* since the value of j-th column is fractional, the column is
alpar@1
   216
            basic; compute corresponding row of the simplex table */
alpar@1
   217
         len = glp_eval_tab_row(mip, m+j, ind, val);
alpar@1
   218
         /* the following fragment computes a change in the objective
alpar@1
   219
            function: delta Z = new Z - old Z, where old Z is the
alpar@1
   220
            objective value in the current optimal basis, and new Z is
alpar@1
   221
            the objective value in the adjacent basis, for two cases:
alpar@1
   222
            1) if new upper bound ub' = floor(x[j]) is introduced for
alpar@1
   223
               j-th column (down branch);
alpar@1
   224
            2) if new lower bound lb' = ceil(x[j]) is introduced for
alpar@1
   225
               j-th column (up branch);
alpar@1
   226
            since in both cases the solution remaining dual feasible
alpar@1
   227
            becomes primal infeasible, one implicit simplex iteration
alpar@1
   228
            is performed to determine the change delta Z;
alpar@1
   229
            it is obvious that new Z, which is never better than old Z,
alpar@1
   230
            is a lower (minimization) or upper (maximization) bound of
alpar@1
   231
            the objective function for down- and up-branches. */
alpar@1
   232
         for (kase = -1; kase <= +1; kase += 2)
alpar@1
   233
         {  /* if kase < 0, the new upper bound of x[j] is introduced;
alpar@1
   234
               in this case x[j] should decrease in order to leave the
alpar@1
   235
               basis and go to its new upper bound */
alpar@1
   236
            /* if kase > 0, the new lower bound of x[j] is introduced;
alpar@1
   237
               in this case x[j] should increase in order to leave the
alpar@1
   238
               basis and go to its new lower bound */
alpar@1
   239
            /* apply the dual ratio test in order to determine which
alpar@1
   240
               auxiliary or structural variable should enter the basis
alpar@1
   241
               to keep dual feasibility */
alpar@1
   242
            k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9);
alpar@1
   243
            if (k != 0) k = ind[k];
alpar@1
   244
            /* if no non-basic variable has been chosen, LP relaxation
alpar@1
   245
               of corresponding branch being primal infeasible and dual
alpar@1
   246
               unbounded has no primal feasible solution; in this case
alpar@1
   247
               the change delta Z is formally set to infinity */
alpar@1
   248
            if (k == 0)
alpar@1
   249
            {  delta_z =
alpar@1
   250
                  (T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX);
alpar@1
   251
               goto skip;
alpar@1
   252
            }
alpar@1
   253
            /* row of the simplex table that corresponds to non-basic
alpar@1
   254
               variable x[k] choosen by the dual ratio test is:
alpar@1
   255
                  x[j] = ... + alfa * x[k] + ...
alpar@1
   256
               where alfa is the influence coefficient (an element of
alpar@1
   257
               the simplex table row) */
alpar@1
   258
            /* determine the coefficient alfa */
alpar@1
   259
            for (t = 1; t <= len; t++) if (ind[t] == k) break;
alpar@1
   260
            xassert(1 <= t && t <= len);
alpar@1
   261
            alfa = val[t];
alpar@1
   262
            /* since in the adjacent basis the variable x[j] becomes
alpar@1
   263
               non-basic, knowing its value in the current basis we can
alpar@1
   264
               determine its change delta x[j] = new x[j] - old x[j] */
alpar@1
   265
            delta_j = (kase < 0 ? floor(x) : ceil(x)) - x;
alpar@1
   266
            /* and knowing the coefficient alfa we can determine the
alpar@1
   267
               corresponding change delta x[k] = new x[k] - old x[k],
alpar@1
   268
               where old x[k] is a value of x[k] in the current basis,
alpar@1
   269
               and new x[k] is a value of x[k] in the adjacent basis */
alpar@1
   270
            delta_k = delta_j / alfa;
alpar@1
   271
            /* Tomlin noticed that if the variable x[k] is of integer
alpar@1
   272
               kind, its change cannot be less (eventually) than one in
alpar@1
   273
               the magnitude */
alpar@1
   274
            if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV)
alpar@1
   275
            {  /* x[k] is structural integer variable */
alpar@1
   276
               if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3)
alpar@1
   277
               {  if (delta_k > 0.0)
alpar@1
   278
                     delta_k = ceil(delta_k);  /* +3.14 -> +4 */
alpar@1
   279
                  else
alpar@1
   280
                     delta_k = floor(delta_k); /* -3.14 -> -4 */
alpar@1
   281
               }
alpar@1
   282
            }
alpar@1
   283
            /* now determine the status and reduced cost of x[k] in the
alpar@1
   284
               current basis */
alpar@1
   285
            if (k <= m)
alpar@1
   286
            {  stat = glp_get_row_stat(mip, k);
alpar@1
   287
               dk = glp_get_row_dual(mip, k);
alpar@1
   288
            }
alpar@1
   289
            else
alpar@1
   290
            {  stat = glp_get_col_stat(mip, k-m);
alpar@1
   291
               dk = glp_get_col_dual(mip, k-m);
alpar@1
   292
            }
alpar@1
   293
            /* if the current basis is dual degenerate, some reduced
alpar@1
   294
               costs which are close to zero may have wrong sign due to
alpar@1
   295
               round-off errors, so correct the sign of d[k] */
alpar@1
   296
            switch (T->mip->dir)
alpar@1
   297
            {  case GLP_MIN:
alpar@1
   298
                  if (stat == GLP_NL && dk < 0.0 ||
alpar@1
   299
                      stat == GLP_NU && dk > 0.0 ||
alpar@1
   300
                      stat == GLP_NF) dk = 0.0;
alpar@1
   301
                  break;
alpar@1
   302
               case GLP_MAX:
alpar@1
   303
                  if (stat == GLP_NL && dk > 0.0 ||
alpar@1
   304
                      stat == GLP_NU && dk < 0.0 ||
alpar@1
   305
                      stat == GLP_NF) dk = 0.0;
alpar@1
   306
                  break;
alpar@1
   307
               default:
alpar@1
   308
                  xassert(T != T);
alpar@1
   309
            }
alpar@1
   310
            /* now knowing the change of x[k] and its reduced cost d[k]
alpar@1
   311
               we can compute the corresponding change in the objective
alpar@1
   312
               function delta Z = new Z - old Z = d[k] * delta x[k];
alpar@1
   313
               note that due to Tomlin's modification new Z can be even
alpar@1
   314
               worse than in the adjacent basis */
alpar@1
   315
            delta_z = dk * delta_k;
alpar@1
   316
skip:       /* new Z is never better than old Z, therefore the change
alpar@1
   317
               delta Z is always non-negative (in case of minimization)
alpar@1
   318
               or non-positive (in case of maximization) */
alpar@1
   319
            switch (T->mip->dir)
alpar@1
   320
            {  case GLP_MIN: xassert(delta_z >= 0.0); break;
alpar@1
   321
               case GLP_MAX: xassert(delta_z <= 0.0); break;
alpar@1
   322
               default: xassert(T != T);
alpar@1
   323
            }
alpar@1
   324
            /* save the change in the objective fnction for down- and
alpar@1
   325
               up-branches, respectively */
alpar@1
   326
            if (kase < 0) dz_dn = delta_z; else dz_up = delta_z;
alpar@1
   327
         }
alpar@1
   328
         /* thus, in down-branch no integer feasible solution can be
alpar@1
   329
            better than Z + dz_dn, and in up-branch no integer feasible
alpar@1
   330
            solution can be better than Z + dz_up, where Z is value of
alpar@1
   331
            the objective function in the current basis */
alpar@1
   332
         /* following the heuristic by Driebeck and Tomlin we choose a
alpar@1
   333
            column (i.e. structural variable) which provides largest
alpar@1
   334
            degradation of the objective function in some of branches;
alpar@1
   335
            besides, we select the branch with smaller degradation to
alpar@1
   336
            be solved next and keep other branch with larger degradation
alpar@1
   337
            in the active list hoping to minimize the number of further
alpar@1
   338
            backtrackings */
alpar@1
   339
         if (degrad < fabs(dz_dn) || degrad < fabs(dz_up))
alpar@1
   340
         {  jj = j;
alpar@1
   341
            if (fabs(dz_dn) < fabs(dz_up))
alpar@1
   342
            {  /* select down branch to be solved next */
alpar@1
   343
               next = GLP_DN_BRNCH;
alpar@1
   344
               degrad = fabs(dz_up);
alpar@1
   345
            }
alpar@1
   346
            else
alpar@1
   347
            {  /* select up branch to be solved next */
alpar@1
   348
               next = GLP_UP_BRNCH;
alpar@1
   349
               degrad = fabs(dz_dn);
alpar@1
   350
            }
alpar@1
   351
            /* save the objective changes for printing */
alpar@1
   352
            dd_dn = dz_dn, dd_up = dz_up;
alpar@1
   353
            /* if down- or up-branch has no feasible solution, we does
alpar@1
   354
               not need to consider other candidates (in principle, the
alpar@1
   355
               corresponding branch could be pruned right now) */
alpar@1
   356
            if (degrad == DBL_MAX) break;
alpar@1
   357
         }
alpar@1
   358
      }
alpar@1
   359
      /* free working arrays */
alpar@1
   360
      xfree(ind);
alpar@1
   361
      xfree(val);
alpar@1
   362
      /* something must be chosen */
alpar@1
   363
      xassert(1 <= jj && jj <= n);
alpar@1
   364
#if 1 /* 02/XI-2009 */
alpar@1
   365
      if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val)))
alpar@1
   366
      {  jj = branch_mostf(T, &next);
alpar@1
   367
         goto done;
alpar@1
   368
      }
alpar@1
   369
#endif
alpar@1
   370
      if (T->parm->msg_lev >= GLP_MSG_DBG)
alpar@1
   371
      {  xprintf("branch_drtom: column %d chosen to branch on\n", jj);
alpar@1
   372
         if (fabs(dd_dn) == DBL_MAX)
alpar@1
   373
            xprintf("branch_drtom: down-branch is infeasible\n");
alpar@1
   374
         else
alpar@1
   375
            xprintf("branch_drtom: down-branch bound is %.9e\n",
alpar@1
   376
               lpx_get_obj_val(mip) + dd_dn);
alpar@1
   377
         if (fabs(dd_up) == DBL_MAX)
alpar@1
   378
            xprintf("branch_drtom: up-branch   is infeasible\n");
alpar@1
   379
         else
alpar@1
   380
            xprintf("branch_drtom: up-branch   bound is %.9e\n",
alpar@1
   381
               lpx_get_obj_val(mip) + dd_up);
alpar@1
   382
      }
alpar@1
   383
done: *_next = next;
alpar@1
   384
      return jj;
alpar@1
   385
}
alpar@1
   386
alpar@1
   387
/**********************************************************************/
alpar@1
   388
alpar@1
   389
struct csa
alpar@1
   390
{     /* common storage area */
alpar@1
   391
      int *dn_cnt; /* int dn_cnt[1+n]; */
alpar@1
   392
      /* dn_cnt[j] is the number of subproblems, whose LP relaxations
alpar@1
   393
         have been solved and which are down-branches for variable x[j];
alpar@1
   394
         dn_cnt[j] = 0 means the down pseudocost is uninitialized */
alpar@1
   395
      double *dn_sum; /* double dn_sum[1+n]; */
alpar@1
   396
      /* dn_sum[j] is the sum of per unit degradations of the objective
alpar@1
   397
         over all dn_cnt[j] subproblems */
alpar@1
   398
      int *up_cnt; /* int up_cnt[1+n]; */
alpar@1
   399
      /* up_cnt[j] is the number of subproblems, whose LP relaxations
alpar@1
   400
         have been solved and which are up-branches for variable x[j];
alpar@1
   401
         up_cnt[j] = 0 means the up pseudocost is uninitialized */
alpar@1
   402
      double *up_sum; /* double up_sum[1+n]; */
alpar@1
   403
      /* up_sum[j] is the sum of per unit degradations of the objective
alpar@1
   404
         over all up_cnt[j] subproblems */
alpar@1
   405
};
alpar@1
   406
alpar@1
   407
void *ios_pcost_init(glp_tree *tree)
alpar@1
   408
{     /* initialize working data used on pseudocost branching */
alpar@1
   409
      struct csa *csa;
alpar@1
   410
      int n = tree->n, j;
alpar@1
   411
      csa = xmalloc(sizeof(struct csa));
alpar@1
   412
      csa->dn_cnt = xcalloc(1+n, sizeof(int));
alpar@1
   413
      csa->dn_sum = xcalloc(1+n, sizeof(double));
alpar@1
   414
      csa->up_cnt = xcalloc(1+n, sizeof(int));
alpar@1
   415
      csa->up_sum = xcalloc(1+n, sizeof(double));
alpar@1
   416
      for (j = 1; j <= n; j++)
alpar@1
   417
      {  csa->dn_cnt[j] = csa->up_cnt[j] = 0;
alpar@1
   418
         csa->dn_sum[j] = csa->up_sum[j] = 0.0;
alpar@1
   419
      }
alpar@1
   420
      return csa;
alpar@1
   421
}
alpar@1
   422
alpar@1
   423
static double eval_degrad(glp_prob *P, int j, double bnd)
alpar@1
   424
{     /* compute degradation of the objective on fixing x[j] at given
alpar@1
   425
         value with a limited number of dual simplex iterations */
alpar@1
   426
      /* this routine fixes column x[j] at specified value bnd,
alpar@1
   427
         solves resulting LP, and returns a lower bound to degradation
alpar@1
   428
         of the objective, degrad >= 0 */
alpar@1
   429
      glp_prob *lp;
alpar@1
   430
      glp_smcp parm;
alpar@1
   431
      int ret;
alpar@1
   432
      double degrad;
alpar@1
   433
      /* the current basis must be optimal */
alpar@1
   434
      xassert(glp_get_status(P) == GLP_OPT);
alpar@1
   435
      /* create a copy of P */
alpar@1
   436
      lp = glp_create_prob();
alpar@1
   437
      glp_copy_prob(lp, P, 0);
alpar@1
   438
      /* fix column x[j] at specified value */
alpar@1
   439
      glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd);
alpar@1
   440
      /* try to solve resulting LP */
alpar@1
   441
      glp_init_smcp(&parm);
alpar@1
   442
      parm.msg_lev = GLP_MSG_OFF;
alpar@1
   443
      parm.meth = GLP_DUAL;
alpar@1
   444
      parm.it_lim = 30;
alpar@1
   445
      parm.out_dly = 1000;
alpar@1
   446
      parm.meth = GLP_DUAL;
alpar@1
   447
      ret = glp_simplex(lp, &parm);
alpar@1
   448
      if (ret == 0 || ret == GLP_EITLIM)
alpar@1
   449
      {  if (glp_get_prim_stat(lp) == GLP_NOFEAS)
alpar@1
   450
         {  /* resulting LP has no primal feasible solution */
alpar@1
   451
            degrad = DBL_MAX;
alpar@1
   452
         }
alpar@1
   453
         else if (glp_get_dual_stat(lp) == GLP_FEAS)
alpar@1
   454
         {  /* resulting basis is optimal or at least dual feasible,
alpar@1
   455
               so we have the correct lower bound to degradation */
alpar@1
   456
            if (P->dir == GLP_MIN)
alpar@1
   457
               degrad = lp->obj_val - P->obj_val;
alpar@1
   458
            else if (P->dir == GLP_MAX)
alpar@1
   459
               degrad = P->obj_val - lp->obj_val;
alpar@1
   460
            else
alpar@1
   461
               xassert(P != P);
alpar@1
   462
            /* degradation cannot be negative by definition */
alpar@1
   463
            /* note that the lower bound to degradation may be close
alpar@1
   464
               to zero even if its exact value is zero due to round-off
alpar@1
   465
               errors on computing the objective value */
alpar@1
   466
            if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val)))
alpar@1
   467
               degrad = 0.0;
alpar@1
   468
         }
alpar@1
   469
         else
alpar@1
   470
         {  /* the final basis reported by the simplex solver is dual
alpar@1
   471
               infeasible, so we cannot determine a non-trivial lower
alpar@1
   472
               bound to degradation */
alpar@1
   473
            degrad = 0.0;
alpar@1
   474
         }
alpar@1
   475
      }
alpar@1
   476
      else
alpar@1
   477
      {  /* the simplex solver failed */
alpar@1
   478
         degrad = 0.0;
alpar@1
   479
      }
alpar@1
   480
      /* delete the copy of P */
alpar@1
   481
      glp_delete_prob(lp);
alpar@1
   482
      return degrad;
alpar@1
   483
}
alpar@1
   484
alpar@1
   485
void ios_pcost_update(glp_tree *tree)
alpar@1
   486
{     /* update history information for pseudocost branching */
alpar@1
   487
      /* this routine is called every time when LP relaxation of the
alpar@1
   488
         current subproblem has been solved to optimality with all lazy
alpar@1
   489
         and cutting plane constraints included */
alpar@1
   490
      int j;
alpar@1
   491
      double dx, dz, psi;
alpar@1
   492
      struct csa *csa = tree->pcost;
alpar@1
   493
      xassert(csa != NULL);
alpar@1
   494
      xassert(tree->curr != NULL);
alpar@1
   495
      /* if the current subproblem is the root, skip updating */
alpar@1
   496
      if (tree->curr->up == NULL) goto skip;
alpar@1
   497
      /* determine branching variable x[j], which was used in the
alpar@1
   498
         parent subproblem to create the current subproblem */
alpar@1
   499
      j = tree->curr->up->br_var;
alpar@1
   500
      xassert(1 <= j && j <= tree->n);
alpar@1
   501
      /* determine the change dx[j] = new x[j] - old x[j],
alpar@1
   502
         where new x[j] is a value of x[j] in optimal solution to LP
alpar@1
   503
         relaxation of the current subproblem, old x[j] is a value of
alpar@1
   504
         x[j] in optimal solution to LP relaxation of the parent
alpar@1
   505
         subproblem */
alpar@1
   506
      dx = tree->mip->col[j]->prim - tree->curr->up->br_val;
alpar@1
   507
      xassert(dx != 0.0);
alpar@1
   508
      /* determine corresponding change dz = new dz - old dz in the
alpar@1
   509
         objective function value */
alpar@1
   510
      dz = tree->mip->obj_val - tree->curr->up->lp_obj;
alpar@1
   511
      /* determine per unit degradation of the objective function */
alpar@1
   512
      psi = fabs(dz / dx);
alpar@1
   513
      /* update history information */
alpar@1
   514
      if (dx < 0.0)
alpar@1
   515
      {  /* the current subproblem is down-branch */
alpar@1
   516
         csa->dn_cnt[j]++;
alpar@1
   517
         csa->dn_sum[j] += psi;
alpar@1
   518
      }
alpar@1
   519
      else /* dx > 0.0 */
alpar@1
   520
      {  /* the current subproblem is up-branch */
alpar@1
   521
         csa->up_cnt[j]++;
alpar@1
   522
         csa->up_sum[j] += psi;
alpar@1
   523
      }
alpar@1
   524
skip: return;
alpar@1
   525
}
alpar@1
   526
alpar@1
   527
void ios_pcost_free(glp_tree *tree)
alpar@1
   528
{     /* free working area used on pseudocost branching */
alpar@1
   529
      struct csa *csa = tree->pcost;
alpar@1
   530
      xassert(csa != NULL);
alpar@1
   531
      xfree(csa->dn_cnt);
alpar@1
   532
      xfree(csa->dn_sum);
alpar@1
   533
      xfree(csa->up_cnt);
alpar@1
   534
      xfree(csa->up_sum);
alpar@1
   535
      xfree(csa);
alpar@1
   536
      tree->pcost = NULL;
alpar@1
   537
      return;
alpar@1
   538
}
alpar@1
   539
alpar@1
   540
static double eval_psi(glp_tree *T, int j, int brnch)
alpar@1
   541
{     /* compute estimation of pseudocost of variable x[j] for down-
alpar@1
   542
         or up-branch */
alpar@1
   543
      struct csa *csa = T->pcost;
alpar@1
   544
      double beta, degrad, psi;
alpar@1
   545
      xassert(csa != NULL);
alpar@1
   546
      xassert(1 <= j && j <= T->n);
alpar@1
   547
      if (brnch == GLP_DN_BRNCH)
alpar@1
   548
      {  /* down-branch */
alpar@1
   549
         if (csa->dn_cnt[j] == 0)
alpar@1
   550
         {  /* initialize down pseudocost */
alpar@1
   551
            beta = T->mip->col[j]->prim;
alpar@1
   552
            degrad = eval_degrad(T->mip, j, floor(beta));
alpar@1
   553
            if (degrad == DBL_MAX)
alpar@1
   554
            {  psi = DBL_MAX;
alpar@1
   555
               goto done;
alpar@1
   556
            }
alpar@1
   557
            csa->dn_cnt[j] = 1;
alpar@1
   558
            csa->dn_sum[j] = degrad / (beta - floor(beta));
alpar@1
   559
         }
alpar@1
   560
         psi = csa->dn_sum[j] / (double)csa->dn_cnt[j];
alpar@1
   561
      }
alpar@1
   562
      else if (brnch == GLP_UP_BRNCH)
alpar@1
   563
      {  /* up-branch */
alpar@1
   564
         if (csa->up_cnt[j] == 0)
alpar@1
   565
         {  /* initialize up pseudocost */
alpar@1
   566
            beta = T->mip->col[j]->prim;
alpar@1
   567
            degrad = eval_degrad(T->mip, j, ceil(beta));
alpar@1
   568
            if (degrad == DBL_MAX)
alpar@1
   569
            {  psi = DBL_MAX;
alpar@1
   570
               goto done;
alpar@1
   571
            }
alpar@1
   572
            csa->up_cnt[j] = 1;
alpar@1
   573
            csa->up_sum[j] = degrad / (ceil(beta) - beta);
alpar@1
   574
         }
alpar@1
   575
         psi = csa->up_sum[j] / (double)csa->up_cnt[j];
alpar@1
   576
      }
alpar@1
   577
      else
alpar@1
   578
         xassert(brnch != brnch);
alpar@1
   579
done: return psi;
alpar@1
   580
}
alpar@1
   581
alpar@1
   582
static void progress(glp_tree *T)
alpar@1
   583
{     /* display progress of pseudocost initialization */
alpar@1
   584
      struct csa *csa = T->pcost;
alpar@1
   585
      int j, nv = 0, ni = 0;
alpar@1
   586
      for (j = 1; j <= T->n; j++)
alpar@1
   587
      {  if (glp_ios_can_branch(T, j))
alpar@1
   588
         {  nv++;
alpar@1
   589
            if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++;
alpar@1
   590
         }
alpar@1
   591
      }
alpar@1
   592
      xprintf("Pseudocosts initialized for %d of %d variables\n",
alpar@1
   593
         ni, nv);
alpar@1
   594
      return;
alpar@1
   595
}
alpar@1
   596
alpar@1
   597
int ios_pcost_branch(glp_tree *T, int *_next)
alpar@1
   598
{     /* choose branching variable with pseudocost branching */
alpar@1
   599
      glp_long t = xtime();
alpar@1
   600
      int j, jjj, sel;
alpar@1
   601
      double beta, psi, d1, d2, d, dmax;
alpar@1
   602
      /* initialize the working arrays */
alpar@1
   603
      if (T->pcost == NULL)
alpar@1
   604
         T->pcost = ios_pcost_init(T);
alpar@1
   605
      /* nothing has been chosen so far */
alpar@1
   606
      jjj = 0, dmax = -1.0;
alpar@1
   607
      /* go through the list of branching candidates */
alpar@1
   608
      for (j = 1; j <= T->n; j++)
alpar@1
   609
      {  if (!glp_ios_can_branch(T, j)) continue;
alpar@1
   610
         /* determine primal value of x[j] in optimal solution to LP
alpar@1
   611
            relaxation of the current subproblem */
alpar@1
   612
         beta = T->mip->col[j]->prim;
alpar@1
   613
         /* estimate pseudocost of x[j] for down-branch */
alpar@1
   614
         psi = eval_psi(T, j, GLP_DN_BRNCH);
alpar@1
   615
         if (psi == DBL_MAX)
alpar@1
   616
         {  /* down-branch has no primal feasible solution */
alpar@1
   617
            jjj = j, sel = GLP_DN_BRNCH;
alpar@1
   618
            goto done;
alpar@1
   619
         }
alpar@1
   620
         /* estimate degradation of the objective for down-branch */
alpar@1
   621
         d1 = psi * (beta - floor(beta));
alpar@1
   622
         /* estimate pseudocost of x[j] for up-branch */
alpar@1
   623
         psi = eval_psi(T, j, GLP_UP_BRNCH);
alpar@1
   624
         if (psi == DBL_MAX)
alpar@1
   625
         {  /* up-branch has no primal feasible solution */
alpar@1
   626
            jjj = j, sel = GLP_UP_BRNCH;
alpar@1
   627
            goto done;
alpar@1
   628
         }
alpar@1
   629
         /* estimate degradation of the objective for up-branch */
alpar@1
   630
         d2 = psi * (ceil(beta) - beta);
alpar@1
   631
         /* determine d = max(d1, d2) */
alpar@1
   632
         d = (d1 > d2 ? d1 : d2);
alpar@1
   633
         /* choose x[j] which provides maximal estimated degradation of
alpar@1
   634
            the objective either in down- or up-branch */
alpar@1
   635
         if (dmax < d)
alpar@1
   636
         {  dmax = d;
alpar@1
   637
            jjj = j;
alpar@1
   638
            /* continue the search from a subproblem, where degradation
alpar@1
   639
               is less than in other one */
alpar@1
   640
            sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH);
alpar@1
   641
         }
alpar@1
   642
         /* display progress of pseudocost initialization */
alpar@1
   643
         if (T->parm->msg_lev >= GLP_ON)
alpar@1
   644
         {  if (xdifftime(xtime(), t) >= 10.0)
alpar@1
   645
            {  progress(T);
alpar@1
   646
               t = xtime();
alpar@1
   647
            }
alpar@1
   648
         }
alpar@1
   649
      }
alpar@1
   650
      if (dmax == 0.0)
alpar@1
   651
      {  /* no degradation is indicated; choose a variable having most
alpar@1
   652
            fractional value */
alpar@1
   653
         jjj = branch_mostf(T, &sel);
alpar@1
   654
      }
alpar@1
   655
done: *_next = sel;
alpar@1
   656
      return jjj;
alpar@1
   657
}
alpar@1
   658
alpar@1
   659
/* eof */