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 */
|