1 /* glpios07.c (mixed cover cut generator) */
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
9 * E-mail: <mao@gnu.org>.
11 * GLPK is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 * License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
23 ***********************************************************************/
27 /*----------------------------------------------------------------------
30 -- Consider the set of feasible solutions to 0-1 knapsack problem:
32 -- sum a[j]*x[j] <= b, (1)
35 -- x[j] is binary, (2)
37 -- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be
38 -- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0).
40 -- A set C within J is called a cover if
45 -- For any cover C the inequality
47 -- sum x[j] <= |C| - 1 (4)
50 -- is called a cover inequality and is valid for (1)-(2).
52 -- MIXED COVER INEQUALITIES
54 -- Consider the set of feasible solutions to mixed knapsack problem:
56 -- sum a[j]*x[j] + y <= b, (5)
59 -- x[j] is binary, (6)
61 -- 0 <= y <= u is continuous, (7)
63 -- where again we assume that a[j] > 0.
65 -- Let C within J be some set. From (1)-(4) it follows that
67 -- sum a[j] > b - y (8)
72 -- sum x[j] <= |C| - 1. (9)
75 -- Thus, we need to modify the inequality (9) in such a way that it be
76 -- a constraint only if the condition (8) is satisfied.
78 -- Consider the following inequality:
80 -- sum x[j] <= |C| - t. (10)
83 -- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are
84 -- binary variables. On the other hand, if t <= 0, (10) being satisfied
85 -- for any values of x[j] is not a constraint.
89 -- t' = sum a[j] + y - b. (11)
92 -- It is understood that the condition t' > 0 is equivalent to (8).
93 -- Besides, from (6)-(7) it follows that t' has an implied upper bound:
95 -- t'max = sum a[j] + u - b. (12)
98 -- This allows to express the parameter t having desired properties:
100 -- t = t' / t'max. (13)
102 -- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0
103 -- is equivalent to (8).
105 -- Thus, the inequality (10), where t is given by formula (13) is valid
108 -- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and
109 -- (10) is transformed to the conditions (3) and (4).
111 -- GENERATING MIXED COVER CUTS
113 -- To generate a mixed cover cut in the form (10) we need to find such
114 -- set C which satisfies to the inequality (8) and for which, in turn,
115 -- the inequality (10) is violated in the current point.
117 -- Substituting t from (13) to (10) gives:
120 -- sum x[j] <= |C| - ----- (sum a[j] + y - b), (14)
121 -- j in C t'max j in C
123 -- and finally we have the cut inequality in the standard form:
125 -- sum x[j] + alfa * y <= beta, (15)
130 -- alfa = 1 / t'max, (16)
132 -- beta = |C| - alfa * (sum a[j] - b). (17)
141 static int cover2(int n, double a[], double b, double u, double x[],
142 double y, int cov[], double *_alfa, double *_beta)
143 { /* try to generate mixed cover cut using two-element cover */
144 int i, j, try = 0, ret = 0;
145 double eps, alfa, beta, temp, rmax = 0.001;
146 eps = 0.001 * (1.0 + fabs(b));
147 for (i = 0+1; i <= n; i++)
148 for (j = i+1; j <= n; j++)
151 if (try > MAXTRY) goto done;
152 /* check if condition (8) is satisfied */
153 if (a[i] + a[j] + y > b + eps)
154 { /* compute parameters for inequality (15) */
155 temp = a[i] + a[j] - b;
156 alfa = 1.0 / (temp + u);
157 beta = 2.0 - alfa * temp;
158 /* compute violation of inequality (15) */
159 temp = x[i] + x[j] + alfa * y - beta;
160 /* choose C providing maximum violation */
174 static int cover3(int n, double a[], double b, double u, double x[],
175 double y, int cov[], double *_alfa, double *_beta)
176 { /* try to generate mixed cover cut using three-element cover */
177 int i, j, k, try = 0, ret = 0;
178 double eps, alfa, beta, temp, rmax = 0.001;
179 eps = 0.001 * (1.0 + fabs(b));
180 for (i = 0+1; i <= n; i++)
181 for (j = i+1; j <= n; j++)
182 for (k = j+1; k <= n; k++)
183 { /* C = {i, j, k} */
185 if (try > MAXTRY) goto done;
186 /* check if condition (8) is satisfied */
187 if (a[i] + a[j] + a[k] + y > b + eps)
188 { /* compute parameters for inequality (15) */
189 temp = a[i] + a[j] + a[k] - b;
190 alfa = 1.0 / (temp + u);
191 beta = 3.0 - alfa * temp;
192 /* compute violation of inequality (15) */
193 temp = x[i] + x[j] + x[k] + alfa * y - beta;
194 /* choose C providing maximum violation */
209 static int cover4(int n, double a[], double b, double u, double x[],
210 double y, int cov[], double *_alfa, double *_beta)
211 { /* try to generate mixed cover cut using four-element cover */
212 int i, j, k, l, try = 0, ret = 0;
213 double eps, alfa, beta, temp, rmax = 0.001;
214 eps = 0.001 * (1.0 + fabs(b));
215 for (i = 0+1; i <= n; i++)
216 for (j = i+1; j <= n; j++)
217 for (k = j+1; k <= n; k++)
218 for (l = k+1; l <= n; l++)
219 { /* C = {i, j, k, l} */
221 if (try > MAXTRY) goto done;
222 /* check if condition (8) is satisfied */
223 if (a[i] + a[j] + a[k] + a[l] + y > b + eps)
224 { /* compute parameters for inequality (15) */
225 temp = a[i] + a[j] + a[k] + a[l] - b;
226 alfa = 1.0 / (temp + u);
227 beta = 4.0 - alfa * temp;
228 /* compute violation of inequality (15) */
229 temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta;
230 /* choose C providing maximum violation */
246 static int cover(int n, double a[], double b, double u, double x[],
247 double y, int cov[], double *alfa, double *beta)
248 { /* try to generate mixed cover cut;
250 n is the number of binary variables;
251 a[1:n] are coefficients at binary variables;
252 b is the right-hand side;
253 u is upper bound of continuous variable;
254 x[1:n] are values of binary variables at current point;
255 y is value of continuous variable at current point;
256 output (see (15), (16), (17)):
257 cov[1:r] are indices of binary variables included in cover C,
258 where r is the set cardinality returned on exit;
259 alfa coefficient at continuous variable;
260 beta is the right-hand side; */
262 /* perform some sanity checks */
264 for (j = 1; j <= n; j++) xassert(a[j] > 0.0);
271 for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0);
272 xassert(0.0 <= y && y <= u);
273 /* try to generate mixed cover cut */
274 if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2;
275 if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3;
276 if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4;
280 /*----------------------------------------------------------------------
281 -- lpx_cover_cut - generate mixed cover cut.
285 -- #include "glplpx.h"
286 -- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
291 -- The routine lpx_cover_cut generates a mixed cover cut for a given
292 -- row of the MIP problem.
294 -- The given row of the MIP problem should be explicitly specified in
297 -- sum{j in J} a[j]*x[j] <= b. (1)
299 -- On entry indices (ordinal numbers) of structural variables, which
300 -- have non-zero constraint coefficients, should be placed in locations
301 -- ind[1], ..., ind[len], and corresponding constraint coefficients
302 -- should be placed in locations val[1], ..., val[len]. The right-hand
303 -- side b should be stored in location val[0].
305 -- The working array work should have at least nb locations, where nb
306 -- is the number of binary variables in (1).
308 -- The routine generates a mixed cover cut in the same form as (1) and
309 -- stores the cut coefficients and right-hand side in the same way as
310 -- just described above.
314 -- If the cutting plane has been successfully generated, the routine
315 -- returns 1 <= len' <= n, which is the number of non-zero coefficients
316 -- in the inequality constraint. Otherwise, the routine returns zero. */
318 static int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
320 { int cov[1+4], j, k, nb, newlen, r;
321 double f_min, f_max, alfa, beta, u, *x = work, y;
322 /* substitute and remove fixed variables */
324 for (k = 1; k <= len; k++)
326 if (lpx_get_col_type(lp, j) == LPX_FX)
327 val[0] -= val[k] * lpx_get_col_lb(lp, j);
330 ind[newlen] = ind[k];
331 val[newlen] = val[k];
335 /* move binary variables to the beginning of the list so that
336 elements 1, 2, ..., nb correspond to binary variables, and
337 elements nb+1, nb+2, ..., len correspond to rest variables */
339 for (k = 1; k <= len; k++)
341 if (lpx_get_col_kind(lp, j) == LPX_IV &&
342 lpx_get_col_type(lp, j) == LPX_DB &&
343 lpx_get_col_lb(lp, j) == 0.0 &&
344 lpx_get_col_ub(lp, j) == 1.0)
345 { /* binary variable */
349 ind_k = ind[nb], val_k = val[nb];
350 ind[nb] = ind[k], val[nb] = val[k];
351 ind[k] = ind_k, val[k] = val_k;
354 /* now the specified row has the form:
355 sum a[j]*x[j] + sum a[j]*y[j] <= b,
356 where x[j] are binary variables, y[j] are rest variables */
357 /* at least two binary variables are needed */
358 if (nb < 2) return 0;
359 /* compute implied lower and upper bounds for sum a[j]*y[j] */
361 for (k = nb+1; k <= len; k++)
363 /* both bounds must be finite */
364 if (lpx_get_col_type(lp, j) != LPX_DB) return 0;
366 { f_min += val[k] * lpx_get_col_lb(lp, j);
367 f_max += val[k] * lpx_get_col_ub(lp, j);
370 { f_min += val[k] * lpx_get_col_ub(lp, j);
371 f_max += val[k] * lpx_get_col_lb(lp, j);
374 /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===>
375 sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===>
376 sum a[j]*x[j] + y <= b - f_min,
377 where y = sum a[j]*y[j] - f_min;
378 note that 0 <= y <= u, u = f_max - f_min */
379 /* determine upper bound of y */
381 /* determine value of y at the current point */
383 for (k = nb+1; k <= len; k++)
385 y += val[k] * lpx_get_col_prim(lp, j);
388 if (y < 0.0) y = 0.0;
390 /* modify the right-hand side b */
392 /* now the transformed row has the form:
393 sum a[j]*x[j] + y <= b, where 0 <= y <= u */
394 /* determine values of x[j] at the current point */
395 for (k = 1; k <= nb; k++)
397 x[k] = lpx_get_col_prim(lp, j);
398 if (x[k] < 0.0) x[k] = 0.0;
399 if (x[k] > 1.0) x[k] = 1.0;
401 /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */
402 for (k = 1; k <= nb; k++)
410 /* try to generate a mixed cover cut for the transformed row */
411 r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta);
412 if (r == 0) return 0;
413 xassert(2 <= r && r <= 4);
414 /* now the cut is in the form:
415 sum{j in C} x[j] + alfa * y <= beta */
416 /* store the right-hand side beta */
417 ind[0] = 0, val[0] = beta;
418 /* restore the original ordinal numbers of x[j] */
419 for (j = 1; j <= r; j++) cov[j] = ind[cov[j]];
420 /* store cut coefficients at binary variables complementing back
421 the variables having negative row coefficients */
423 for (k = 1; k <= r; k++)
434 /* substitute y = sum a[j]*y[j] - f_min */
435 for (k = nb+1; k <= len; k++)
438 val[r] = alfa * val[k];
440 val[0] += alfa * f_min;
446 /*----------------------------------------------------------------------
447 -- lpx_eval_row - compute explictily specified row.
451 -- #include "glplpx.h"
452 -- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]);
456 -- The routine lpx_eval_row computes the primal value of an explicitly
457 -- specified row using current values of structural variables.
459 -- The explicitly specified row may be thought as a linear form:
461 -- y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],
463 -- where y is an auxiliary variable for this row, a[j] are coefficients
464 -- of the linear form, x[m+j] are structural variables.
466 -- On entry column indices and numerical values of non-zero elements of
467 -- the row should be stored in locations ind[1], ..., ind[len] and
468 -- val[1], ..., val[len], where len is the number of non-zero elements.
469 -- The array ind and val are not changed on exit.
473 -- The routine returns a computed value of y, the auxiliary variable of
474 -- the specified row. */
476 static double lpx_eval_row(LPX *lp, int len, int ind[], double val[])
477 { int n = lpx_get_num_cols(lp);
481 xerror("lpx_eval_row: len = %d; invalid row length\n", len);
482 for (k = 1; k <= len; k++)
484 if (!(1 <= j && j <= n))
485 xerror("lpx_eval_row: j = %d; column number out of range\n",
487 sum += val[k] * lpx_get_col_prim(lp, j);
492 /***********************************************************************
495 * ios_cov_gen - generate mixed cover cuts
499 * #include "glpios.h"
500 * void ios_cov_gen(glp_tree *tree);
504 * The routine ios_cov_gen generates mixed cover cuts for the current
505 * point and adds them to the cut pool. */
507 void ios_cov_gen(glp_tree *tree)
508 { glp_prob *prob = tree->mip;
509 int m = lpx_get_num_rows(prob);
510 int n = lpx_get_num_cols(prob);
511 int i, k, type, kase, len, *ind;
512 double r, *val, *work;
513 xassert(lpx_get_status(prob) == LPX_OPT);
514 /* allocate working arrays */
515 ind = xcalloc(1+n, sizeof(int));
516 val = xcalloc(1+n, sizeof(double));
517 work = xcalloc(1+n, sizeof(double));
518 /* look through all rows */
519 for (i = 1; i <= m; i++)
520 for (kase = 1; kase <= 2; kase++)
521 { type = lpx_get_row_type(prob, i);
523 { /* consider rows of '<=' type */
524 if (!(type == LPX_UP || type == LPX_DB)) continue;
525 len = lpx_get_mat_row(prob, i, ind, val);
526 val[0] = lpx_get_row_ub(prob, i);
529 { /* consider rows of '>=' type */
530 if (!(type == LPX_LO || type == LPX_DB)) continue;
531 len = lpx_get_mat_row(prob, i, ind, val);
532 for (k = 1; k <= len; k++) val[k] = - val[k];
533 val[0] = - lpx_get_row_lb(prob, i);
535 /* generate mixed cover cut:
536 sum{j in J} a[j] * x[j] <= b */
537 len = lpx_cover_cut(prob, len, ind, val, work);
538 if (len == 0) continue;
539 /* at the current point the cut inequality is violated, i.e.
540 sum{j in J} a[j] * x[j] - b > 0 */
541 r = lpx_eval_row(prob, len, ind, val) - val[0];
542 if (r < 1e-3) continue;
543 /* add the cut to the cut pool */
544 glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val,
547 /* free working arrays */