You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
664 lines
26 KiB
664 lines
26 KiB
/* glpios09.c (branching heuristics) */
|
|
|
|
/***********************************************************************
|
|
* This code is part of GLPK (GNU Linear Programming Kit).
|
|
*
|
|
* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
* 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied
|
|
* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
|
|
* reserved. E-mail: <mao@gnu.org>.
|
|
*
|
|
* GLPK is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GLPK is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
* License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
|
***********************************************************************/
|
|
|
|
#include "env.h"
|
|
#include "glpios.h"
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* ios_choose_var - select variable to branch on
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "glpios.h"
|
|
* int ios_choose_var(glp_tree *T, int *next);
|
|
*
|
|
* The routine ios_choose_var chooses a variable from the candidate
|
|
* list to branch on. Additionally the routine provides a flag stored
|
|
* in the location next to suggests which of the child subproblems
|
|
* should be solved next.
|
|
*
|
|
* RETURNS
|
|
*
|
|
* The routine ios_choose_var returns the ordinal number of the column
|
|
* choosen. */
|
|
|
|
static int branch_first(glp_tree *T, int *next);
|
|
static int branch_last(glp_tree *T, int *next);
|
|
static int branch_mostf(glp_tree *T, int *next);
|
|
static int branch_drtom(glp_tree *T, int *next);
|
|
|
|
int ios_choose_var(glp_tree *T, int *next)
|
|
{ int j;
|
|
if (T->parm->br_tech == GLP_BR_FFV)
|
|
{ /* branch on first fractional variable */
|
|
j = branch_first(T, next);
|
|
}
|
|
else if (T->parm->br_tech == GLP_BR_LFV)
|
|
{ /* branch on last fractional variable */
|
|
j = branch_last(T, next);
|
|
}
|
|
else if (T->parm->br_tech == GLP_BR_MFV)
|
|
{ /* branch on most fractional variable */
|
|
j = branch_mostf(T, next);
|
|
}
|
|
else if (T->parm->br_tech == GLP_BR_DTH)
|
|
{ /* branch using the heuristic by Dreebeck and Tomlin */
|
|
j = branch_drtom(T, next);
|
|
}
|
|
else if (T->parm->br_tech == GLP_BR_PCH)
|
|
{ /* hybrid pseudocost heuristic */
|
|
j = ios_pcost_branch(T, next);
|
|
}
|
|
else
|
|
xassert(T != T);
|
|
return j;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* branch_first - choose first branching variable
|
|
*
|
|
* This routine looks up the list of structural variables and chooses
|
|
* the first one, which is of integer kind and has fractional value in
|
|
* optimal solution to the current LP relaxation.
|
|
*
|
|
* This routine also selects the branch to be solved next where integer
|
|
* infeasibility of the chosen variable is less than in other one. */
|
|
|
|
static int branch_first(glp_tree *T, int *_next)
|
|
{ int j, next;
|
|
double beta;
|
|
/* choose the column to branch on */
|
|
for (j = 1; j <= T->n; j++)
|
|
if (T->non_int[j]) break;
|
|
xassert(1 <= j && j <= T->n);
|
|
/* select the branch to be solved next */
|
|
beta = glp_get_col_prim(T->mip, j);
|
|
if (beta - floor(beta) < ceil(beta) - beta)
|
|
next = GLP_DN_BRNCH;
|
|
else
|
|
next = GLP_UP_BRNCH;
|
|
*_next = next;
|
|
return j;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* branch_last - choose last branching variable
|
|
*
|
|
* This routine looks up the list of structural variables and chooses
|
|
* the last one, which is of integer kind and has fractional value in
|
|
* optimal solution to the current LP relaxation.
|
|
*
|
|
* This routine also selects the branch to be solved next where integer
|
|
* infeasibility of the chosen variable is less than in other one. */
|
|
|
|
static int branch_last(glp_tree *T, int *_next)
|
|
{ int j, next;
|
|
double beta;
|
|
/* choose the column to branch on */
|
|
for (j = T->n; j >= 1; j--)
|
|
if (T->non_int[j]) break;
|
|
xassert(1 <= j && j <= T->n);
|
|
/* select the branch to be solved next */
|
|
beta = glp_get_col_prim(T->mip, j);
|
|
if (beta - floor(beta) < ceil(beta) - beta)
|
|
next = GLP_DN_BRNCH;
|
|
else
|
|
next = GLP_UP_BRNCH;
|
|
*_next = next;
|
|
return j;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* branch_mostf - choose most fractional branching variable
|
|
*
|
|
* This routine looks up the list of structural variables and chooses
|
|
* that one, which is of integer kind and has most fractional value in
|
|
* optimal solution to the current LP relaxation.
|
|
*
|
|
* This routine also selects the branch to be solved next where integer
|
|
* infeasibility of the chosen variable is less than in other one.
|
|
*
|
|
* (Alexander Martin notices that "...most infeasible is as good as
|
|
* random...".) */
|
|
|
|
static int branch_mostf(glp_tree *T, int *_next)
|
|
{ int j, jj, next;
|
|
double beta, most, temp;
|
|
/* choose the column to branch on */
|
|
jj = 0, most = DBL_MAX;
|
|
for (j = 1; j <= T->n; j++)
|
|
{ if (T->non_int[j])
|
|
{ beta = glp_get_col_prim(T->mip, j);
|
|
temp = floor(beta) + 0.5;
|
|
if (most > fabs(beta - temp))
|
|
{ jj = j, most = fabs(beta - temp);
|
|
if (beta < temp)
|
|
next = GLP_DN_BRNCH;
|
|
else
|
|
next = GLP_UP_BRNCH;
|
|
}
|
|
}
|
|
}
|
|
*_next = next;
|
|
return jj;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* branch_drtom - choose branching var using Driebeck-Tomlin heuristic
|
|
*
|
|
* This routine chooses a structural variable, which is required to be
|
|
* integral and has fractional value in optimal solution of the current
|
|
* LP relaxation, using a heuristic proposed by Driebeck and Tomlin.
|
|
*
|
|
* The routine also selects the branch to be solved next, again due to
|
|
* Driebeck and Tomlin.
|
|
*
|
|
* This routine is based on the heuristic proposed in:
|
|
*
|
|
* Driebeck N.J. An algorithm for the solution of mixed-integer
|
|
* programming problems, Management Science, 12: 576-87 (1966);
|
|
*
|
|
* and improved in:
|
|
*
|
|
* Tomlin J.A. Branch and bound methods for integer and non-convex
|
|
* programming, in J.Abadie (ed.), Integer and Nonlinear Programming,
|
|
* North-Holland, Amsterdam, pp. 437-50 (1970).
|
|
*
|
|
* Must note that this heuristic is time-expensive, because computing
|
|
* one-step degradation (see the routine below) requires one BTRAN for
|
|
* each fractional-valued structural variable. */
|
|
|
|
static int branch_drtom(glp_tree *T, int *_next)
|
|
{ glp_prob *mip = T->mip;
|
|
int m = mip->m;
|
|
int n = mip->n;
|
|
unsigned char *non_int = T->non_int;
|
|
int j, jj, k, t, next, kase, len, stat, *ind;
|
|
double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up,
|
|
dd_dn, dd_up, degrad, *val;
|
|
/* basic solution of LP relaxation must be optimal */
|
|
xassert(glp_get_status(mip) == GLP_OPT);
|
|
/* allocate working arrays */
|
|
ind = xcalloc(1+n, sizeof(int));
|
|
val = xcalloc(1+n, sizeof(double));
|
|
/* nothing has been chosen so far */
|
|
jj = 0, degrad = -1.0;
|
|
/* walk through the list of columns (structural variables) */
|
|
for (j = 1; j <= n; j++)
|
|
{ /* if j-th column is not marked as fractional, skip it */
|
|
if (!non_int[j]) continue;
|
|
/* obtain (fractional) value of j-th column in basic solution
|
|
of LP relaxation */
|
|
x = glp_get_col_prim(mip, j);
|
|
/* since the value of j-th column is fractional, the column is
|
|
basic; compute corresponding row of the simplex table */
|
|
len = glp_eval_tab_row(mip, m+j, ind, val);
|
|
/* the following fragment computes a change in the objective
|
|
function: delta Z = new Z - old Z, where old Z is the
|
|
objective value in the current optimal basis, and new Z is
|
|
the objective value in the adjacent basis, for two cases:
|
|
1) if new upper bound ub' = floor(x[j]) is introduced for
|
|
j-th column (down branch);
|
|
2) if new lower bound lb' = ceil(x[j]) is introduced for
|
|
j-th column (up branch);
|
|
since in both cases the solution remaining dual feasible
|
|
becomes primal infeasible, one implicit simplex iteration
|
|
is performed to determine the change delta Z;
|
|
it is obvious that new Z, which is never better than old Z,
|
|
is a lower (minimization) or upper (maximization) bound of
|
|
the objective function for down- and up-branches. */
|
|
for (kase = -1; kase <= +1; kase += 2)
|
|
{ /* if kase < 0, the new upper bound of x[j] is introduced;
|
|
in this case x[j] should decrease in order to leave the
|
|
basis and go to its new upper bound */
|
|
/* if kase > 0, the new lower bound of x[j] is introduced;
|
|
in this case x[j] should increase in order to leave the
|
|
basis and go to its new lower bound */
|
|
/* apply the dual ratio test in order to determine which
|
|
auxiliary or structural variable should enter the basis
|
|
to keep dual feasibility */
|
|
k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9);
|
|
if (k != 0) k = ind[k];
|
|
/* if no non-basic variable has been chosen, LP relaxation
|
|
of corresponding branch being primal infeasible and dual
|
|
unbounded has no primal feasible solution; in this case
|
|
the change delta Z is formally set to infinity */
|
|
if (k == 0)
|
|
{ delta_z =
|
|
(T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX);
|
|
goto skip;
|
|
}
|
|
/* row of the simplex table that corresponds to non-basic
|
|
variable x[k] choosen by the dual ratio test is:
|
|
x[j] = ... + alfa * x[k] + ...
|
|
where alfa is the influence coefficient (an element of
|
|
the simplex table row) */
|
|
/* determine the coefficient alfa */
|
|
for (t = 1; t <= len; t++) if (ind[t] == k) break;
|
|
xassert(1 <= t && t <= len);
|
|
alfa = val[t];
|
|
/* since in the adjacent basis the variable x[j] becomes
|
|
non-basic, knowing its value in the current basis we can
|
|
determine its change delta x[j] = new x[j] - old x[j] */
|
|
delta_j = (kase < 0 ? floor(x) : ceil(x)) - x;
|
|
/* and knowing the coefficient alfa we can determine the
|
|
corresponding change delta x[k] = new x[k] - old x[k],
|
|
where old x[k] is a value of x[k] in the current basis,
|
|
and new x[k] is a value of x[k] in the adjacent basis */
|
|
delta_k = delta_j / alfa;
|
|
/* Tomlin noticed that if the variable x[k] is of integer
|
|
kind, its change cannot be less (eventually) than one in
|
|
the magnitude */
|
|
if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV)
|
|
{ /* x[k] is structural integer variable */
|
|
if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3)
|
|
{ if (delta_k > 0.0)
|
|
delta_k = ceil(delta_k); /* +3.14 -> +4 */
|
|
else
|
|
delta_k = floor(delta_k); /* -3.14 -> -4 */
|
|
}
|
|
}
|
|
/* now determine the status and reduced cost of x[k] in the
|
|
current basis */
|
|
if (k <= m)
|
|
{ stat = glp_get_row_stat(mip, k);
|
|
dk = glp_get_row_dual(mip, k);
|
|
}
|
|
else
|
|
{ stat = glp_get_col_stat(mip, k-m);
|
|
dk = glp_get_col_dual(mip, k-m);
|
|
}
|
|
/* if the current basis is dual degenerate, some reduced
|
|
costs which are close to zero may have wrong sign due to
|
|
round-off errors, so correct the sign of d[k] */
|
|
switch (T->mip->dir)
|
|
{ case GLP_MIN:
|
|
if (stat == GLP_NL && dk < 0.0 ||
|
|
stat == GLP_NU && dk > 0.0 ||
|
|
stat == GLP_NF) dk = 0.0;
|
|
break;
|
|
case GLP_MAX:
|
|
if (stat == GLP_NL && dk > 0.0 ||
|
|
stat == GLP_NU && dk < 0.0 ||
|
|
stat == GLP_NF) dk = 0.0;
|
|
break;
|
|
default:
|
|
xassert(T != T);
|
|
}
|
|
/* now knowing the change of x[k] and its reduced cost d[k]
|
|
we can compute the corresponding change in the objective
|
|
function delta Z = new Z - old Z = d[k] * delta x[k];
|
|
note that due to Tomlin's modification new Z can be even
|
|
worse than in the adjacent basis */
|
|
delta_z = dk * delta_k;
|
|
skip: /* new Z is never better than old Z, therefore the change
|
|
delta Z is always non-negative (in case of minimization)
|
|
or non-positive (in case of maximization) */
|
|
switch (T->mip->dir)
|
|
{ case GLP_MIN: xassert(delta_z >= 0.0); break;
|
|
case GLP_MAX: xassert(delta_z <= 0.0); break;
|
|
default: xassert(T != T);
|
|
}
|
|
/* save the change in the objective fnction for down- and
|
|
up-branches, respectively */
|
|
if (kase < 0) dz_dn = delta_z; else dz_up = delta_z;
|
|
}
|
|
/* thus, in down-branch no integer feasible solution can be
|
|
better than Z + dz_dn, and in up-branch no integer feasible
|
|
solution can be better than Z + dz_up, where Z is value of
|
|
the objective function in the current basis */
|
|
/* following the heuristic by Driebeck and Tomlin we choose a
|
|
column (i.e. structural variable) which provides largest
|
|
degradation of the objective function in some of branches;
|
|
besides, we select the branch with smaller degradation to
|
|
be solved next and keep other branch with larger degradation
|
|
in the active list hoping to minimize the number of further
|
|
backtrackings */
|
|
if (degrad < fabs(dz_dn) || degrad < fabs(dz_up))
|
|
{ jj = j;
|
|
if (fabs(dz_dn) < fabs(dz_up))
|
|
{ /* select down branch to be solved next */
|
|
next = GLP_DN_BRNCH;
|
|
degrad = fabs(dz_up);
|
|
}
|
|
else
|
|
{ /* select up branch to be solved next */
|
|
next = GLP_UP_BRNCH;
|
|
degrad = fabs(dz_dn);
|
|
}
|
|
/* save the objective changes for printing */
|
|
dd_dn = dz_dn, dd_up = dz_up;
|
|
/* if down- or up-branch has no feasible solution, we does
|
|
not need to consider other candidates (in principle, the
|
|
corresponding branch could be pruned right now) */
|
|
if (degrad == DBL_MAX) break;
|
|
}
|
|
}
|
|
/* free working arrays */
|
|
xfree(ind);
|
|
xfree(val);
|
|
/* something must be chosen */
|
|
xassert(1 <= jj && jj <= n);
|
|
#if 1 /* 02/XI-2009 */
|
|
if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val)))
|
|
{ jj = branch_mostf(T, &next);
|
|
goto done;
|
|
}
|
|
#endif
|
|
if (T->parm->msg_lev >= GLP_MSG_DBG)
|
|
{ xprintf("branch_drtom: column %d chosen to branch on\n", jj);
|
|
if (fabs(dd_dn) == DBL_MAX)
|
|
xprintf("branch_drtom: down-branch is infeasible\n");
|
|
else
|
|
xprintf("branch_drtom: down-branch bound is %.9e\n",
|
|
glp_get_obj_val(mip) + dd_dn);
|
|
if (fabs(dd_up) == DBL_MAX)
|
|
xprintf("branch_drtom: up-branch is infeasible\n");
|
|
else
|
|
xprintf("branch_drtom: up-branch bound is %.9e\n",
|
|
glp_get_obj_val(mip) + dd_up);
|
|
}
|
|
done: *_next = next;
|
|
return jj;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
struct csa
|
|
{ /* common storage area */
|
|
int *dn_cnt; /* int dn_cnt[1+n]; */
|
|
/* dn_cnt[j] is the number of subproblems, whose LP relaxations
|
|
have been solved and which are down-branches for variable x[j];
|
|
dn_cnt[j] = 0 means the down pseudocost is uninitialized */
|
|
double *dn_sum; /* double dn_sum[1+n]; */
|
|
/* dn_sum[j] is the sum of per unit degradations of the objective
|
|
over all dn_cnt[j] subproblems */
|
|
int *up_cnt; /* int up_cnt[1+n]; */
|
|
/* up_cnt[j] is the number of subproblems, whose LP relaxations
|
|
have been solved and which are up-branches for variable x[j];
|
|
up_cnt[j] = 0 means the up pseudocost is uninitialized */
|
|
double *up_sum; /* double up_sum[1+n]; */
|
|
/* up_sum[j] is the sum of per unit degradations of the objective
|
|
over all up_cnt[j] subproblems */
|
|
};
|
|
|
|
void *ios_pcost_init(glp_tree *tree)
|
|
{ /* initialize working data used on pseudocost branching */
|
|
struct csa *csa;
|
|
int n = tree->n, j;
|
|
csa = xmalloc(sizeof(struct csa));
|
|
csa->dn_cnt = xcalloc(1+n, sizeof(int));
|
|
csa->dn_sum = xcalloc(1+n, sizeof(double));
|
|
csa->up_cnt = xcalloc(1+n, sizeof(int));
|
|
csa->up_sum = xcalloc(1+n, sizeof(double));
|
|
for (j = 1; j <= n; j++)
|
|
{ csa->dn_cnt[j] = csa->up_cnt[j] = 0;
|
|
csa->dn_sum[j] = csa->up_sum[j] = 0.0;
|
|
}
|
|
return csa;
|
|
}
|
|
|
|
static double eval_degrad(glp_prob *P, int j, double bnd)
|
|
{ /* compute degradation of the objective on fixing x[j] at given
|
|
value with a limited number of dual simplex iterations */
|
|
/* this routine fixes column x[j] at specified value bnd,
|
|
solves resulting LP, and returns a lower bound to degradation
|
|
of the objective, degrad >= 0 */
|
|
glp_prob *lp;
|
|
glp_smcp parm;
|
|
int ret;
|
|
double degrad;
|
|
/* the current basis must be optimal */
|
|
xassert(glp_get_status(P) == GLP_OPT);
|
|
/* create a copy of P */
|
|
lp = glp_create_prob();
|
|
glp_copy_prob(lp, P, 0);
|
|
/* fix column x[j] at specified value */
|
|
glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd);
|
|
/* try to solve resulting LP */
|
|
glp_init_smcp(&parm);
|
|
parm.msg_lev = GLP_MSG_OFF;
|
|
parm.meth = GLP_DUAL;
|
|
parm.it_lim = 30;
|
|
parm.out_dly = 1000;
|
|
parm.meth = GLP_DUAL;
|
|
ret = glp_simplex(lp, &parm);
|
|
if (ret == 0 || ret == GLP_EITLIM)
|
|
{ if (glp_get_prim_stat(lp) == GLP_NOFEAS)
|
|
{ /* resulting LP has no primal feasible solution */
|
|
degrad = DBL_MAX;
|
|
}
|
|
else if (glp_get_dual_stat(lp) == GLP_FEAS)
|
|
{ /* resulting basis is optimal or at least dual feasible,
|
|
so we have the correct lower bound to degradation */
|
|
if (P->dir == GLP_MIN)
|
|
degrad = lp->obj_val - P->obj_val;
|
|
else if (P->dir == GLP_MAX)
|
|
degrad = P->obj_val - lp->obj_val;
|
|
else
|
|
xassert(P != P);
|
|
/* degradation cannot be negative by definition */
|
|
/* note that the lower bound to degradation may be close
|
|
to zero even if its exact value is zero due to round-off
|
|
errors on computing the objective value */
|
|
if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val)))
|
|
degrad = 0.0;
|
|
}
|
|
else
|
|
{ /* the final basis reported by the simplex solver is dual
|
|
infeasible, so we cannot determine a non-trivial lower
|
|
bound to degradation */
|
|
degrad = 0.0;
|
|
}
|
|
}
|
|
else
|
|
{ /* the simplex solver failed */
|
|
degrad = 0.0;
|
|
}
|
|
/* delete the copy of P */
|
|
glp_delete_prob(lp);
|
|
return degrad;
|
|
}
|
|
|
|
void ios_pcost_update(glp_tree *tree)
|
|
{ /* update history information for pseudocost branching */
|
|
/* this routine is called every time when LP relaxation of the
|
|
current subproblem has been solved to optimality with all lazy
|
|
and cutting plane constraints included */
|
|
int j;
|
|
double dx, dz, psi;
|
|
struct csa *csa = tree->pcost;
|
|
xassert(csa != NULL);
|
|
xassert(tree->curr != NULL);
|
|
/* if the current subproblem is the root, skip updating */
|
|
if (tree->curr->up == NULL) goto skip;
|
|
/* determine branching variable x[j], which was used in the
|
|
parent subproblem to create the current subproblem */
|
|
j = tree->curr->up->br_var;
|
|
xassert(1 <= j && j <= tree->n);
|
|
/* determine the change dx[j] = new x[j] - old x[j],
|
|
where new x[j] is a value of x[j] in optimal solution to LP
|
|
relaxation of the current subproblem, old x[j] is a value of
|
|
x[j] in optimal solution to LP relaxation of the parent
|
|
subproblem */
|
|
dx = tree->mip->col[j]->prim - tree->curr->up->br_val;
|
|
xassert(dx != 0.0);
|
|
/* determine corresponding change dz = new dz - old dz in the
|
|
objective function value */
|
|
dz = tree->mip->obj_val - tree->curr->up->lp_obj;
|
|
/* determine per unit degradation of the objective function */
|
|
psi = fabs(dz / dx);
|
|
/* update history information */
|
|
if (dx < 0.0)
|
|
{ /* the current subproblem is down-branch */
|
|
csa->dn_cnt[j]++;
|
|
csa->dn_sum[j] += psi;
|
|
}
|
|
else /* dx > 0.0 */
|
|
{ /* the current subproblem is up-branch */
|
|
csa->up_cnt[j]++;
|
|
csa->up_sum[j] += psi;
|
|
}
|
|
skip: return;
|
|
}
|
|
|
|
void ios_pcost_free(glp_tree *tree)
|
|
{ /* free working area used on pseudocost branching */
|
|
struct csa *csa = tree->pcost;
|
|
xassert(csa != NULL);
|
|
xfree(csa->dn_cnt);
|
|
xfree(csa->dn_sum);
|
|
xfree(csa->up_cnt);
|
|
xfree(csa->up_sum);
|
|
xfree(csa);
|
|
tree->pcost = NULL;
|
|
return;
|
|
}
|
|
|
|
static double eval_psi(glp_tree *T, int j, int brnch)
|
|
{ /* compute estimation of pseudocost of variable x[j] for down-
|
|
or up-branch */
|
|
struct csa *csa = T->pcost;
|
|
double beta, degrad, psi;
|
|
xassert(csa != NULL);
|
|
xassert(1 <= j && j <= T->n);
|
|
if (brnch == GLP_DN_BRNCH)
|
|
{ /* down-branch */
|
|
if (csa->dn_cnt[j] == 0)
|
|
{ /* initialize down pseudocost */
|
|
beta = T->mip->col[j]->prim;
|
|
degrad = eval_degrad(T->mip, j, floor(beta));
|
|
if (degrad == DBL_MAX)
|
|
{ psi = DBL_MAX;
|
|
goto done;
|
|
}
|
|
csa->dn_cnt[j] = 1;
|
|
csa->dn_sum[j] = degrad / (beta - floor(beta));
|
|
}
|
|
psi = csa->dn_sum[j] / (double)csa->dn_cnt[j];
|
|
}
|
|
else if (brnch == GLP_UP_BRNCH)
|
|
{ /* up-branch */
|
|
if (csa->up_cnt[j] == 0)
|
|
{ /* initialize up pseudocost */
|
|
beta = T->mip->col[j]->prim;
|
|
degrad = eval_degrad(T->mip, j, ceil(beta));
|
|
if (degrad == DBL_MAX)
|
|
{ psi = DBL_MAX;
|
|
goto done;
|
|
}
|
|
csa->up_cnt[j] = 1;
|
|
csa->up_sum[j] = degrad / (ceil(beta) - beta);
|
|
}
|
|
psi = csa->up_sum[j] / (double)csa->up_cnt[j];
|
|
}
|
|
else
|
|
xassert(brnch != brnch);
|
|
done: return psi;
|
|
}
|
|
|
|
static void progress(glp_tree *T)
|
|
{ /* display progress of pseudocost initialization */
|
|
struct csa *csa = T->pcost;
|
|
int j, nv = 0, ni = 0;
|
|
for (j = 1; j <= T->n; j++)
|
|
{ if (glp_ios_can_branch(T, j))
|
|
{ nv++;
|
|
if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++;
|
|
}
|
|
}
|
|
xprintf("Pseudocosts initialized for %d of %d variables\n",
|
|
ni, nv);
|
|
return;
|
|
}
|
|
|
|
int ios_pcost_branch(glp_tree *T, int *_next)
|
|
{ /* choose branching variable with pseudocost branching */
|
|
#if 0 /* 10/VI-2013 */
|
|
glp_long t = xtime();
|
|
#else
|
|
double t = xtime();
|
|
#endif
|
|
int j, jjj, sel;
|
|
double beta, psi, d1, d2, d, dmax;
|
|
/* initialize the working arrays */
|
|
if (T->pcost == NULL)
|
|
T->pcost = ios_pcost_init(T);
|
|
/* nothing has been chosen so far */
|
|
jjj = 0, dmax = -1.0;
|
|
/* go through the list of branching candidates */
|
|
for (j = 1; j <= T->n; j++)
|
|
{ if (!glp_ios_can_branch(T, j)) continue;
|
|
/* determine primal value of x[j] in optimal solution to LP
|
|
relaxation of the current subproblem */
|
|
beta = T->mip->col[j]->prim;
|
|
/* estimate pseudocost of x[j] for down-branch */
|
|
psi = eval_psi(T, j, GLP_DN_BRNCH);
|
|
if (psi == DBL_MAX)
|
|
{ /* down-branch has no primal feasible solution */
|
|
jjj = j, sel = GLP_DN_BRNCH;
|
|
goto done;
|
|
}
|
|
/* estimate degradation of the objective for down-branch */
|
|
d1 = psi * (beta - floor(beta));
|
|
/* estimate pseudocost of x[j] for up-branch */
|
|
psi = eval_psi(T, j, GLP_UP_BRNCH);
|
|
if (psi == DBL_MAX)
|
|
{ /* up-branch has no primal feasible solution */
|
|
jjj = j, sel = GLP_UP_BRNCH;
|
|
goto done;
|
|
}
|
|
/* estimate degradation of the objective for up-branch */
|
|
d2 = psi * (ceil(beta) - beta);
|
|
/* determine d = max(d1, d2) */
|
|
d = (d1 > d2 ? d1 : d2);
|
|
/* choose x[j] which provides maximal estimated degradation of
|
|
the objective either in down- or up-branch */
|
|
if (dmax < d)
|
|
{ dmax = d;
|
|
jjj = j;
|
|
/* continue the search from a subproblem, where degradation
|
|
is less than in other one */
|
|
sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH);
|
|
}
|
|
/* display progress of pseudocost initialization */
|
|
if (T->parm->msg_lev >= GLP_ON)
|
|
{ if (xdifftime(xtime(), t) >= 10.0)
|
|
{ progress(T);
|
|
t = xtime();
|
|
}
|
|
}
|
|
}
|
|
if (dmax == 0.0)
|
|
{ /* no degradation is indicated; choose a variable having most
|
|
fractional value */
|
|
jjj = branch_mostf(T, &sel);
|
|
}
|
|
done: *_next = sel;
|
|
return jjj;
|
|
}
|
|
|
|
/* eof */
|