1 /* glpios06.c (MIR 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 ***********************************************************************/
30 /* maximal number of rows which can be aggregated */
33 { /* MIR cut generator working area */
34 /*--------------------------------------------------------------*/
35 /* global information valid for the root subproblem */
37 /* number of rows (in the root subproblem) */
39 /* number of columns */
40 char *skip; /* char skip[1+m]; */
41 /* skip[i], 1 <= i <= m, is a flag that means that row i should
42 not be used because (1) it is not suitable, or (2) because it
43 has been used in the aggregated constraint */
44 char *isint; /* char isint[1+m+n]; */
45 /* isint[k], 1 <= k <= m+n, is a flag that means that variable
46 x[k] is integer (otherwise, continuous) */
47 double *lb; /* double lb[1+m+n]; */
48 /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
49 that x[k] has no lower bound */
50 int *vlb; /* int vlb[1+m+n]; */
51 /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
52 which defines variable lower bound x[k] >= lb[k] * x[k']; zero
53 means that x[k] has simple lower bound */
54 double *ub; /* double ub[1+m+n]; */
55 /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
56 that x[k] has no upper bound */
57 int *vub; /* int vub[1+m+n]; */
58 /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
59 which defines variable upper bound x[k] <= ub[k] * x[k']; zero
60 means that x[k] has simple upper bound */
61 /*--------------------------------------------------------------*/
62 /* current (fractional) point to be separated */
63 double *x; /* double x[1+m+n]; */
64 /* x[k] is current value of auxiliary (1 <= k <= m) or structural
65 (m+1 <= k <= m+n) variable */
66 /*--------------------------------------------------------------*/
67 /* aggregated constraint sum a[k] * x[k] = b, which is a linear
68 combination of original constraints transformed to equalities
69 by introducing auxiliary variables */
71 /* number of rows (original constraints) used to build aggregated
72 constraint, 1 <= agg_cnt <= MAXAGGR */
73 int *agg_row; /* int agg_row[1+MAXAGGR]; */
74 /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
75 aggregated constraint */
76 IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */
77 /* sparse vector of aggregated constraint coefficients, a[k] */
79 /* right-hand side of the aggregated constraint, b */
80 /*--------------------------------------------------------------*/
81 /* bound substitution flags for modified constraint */
82 char *subst; /* char subst[1+m+n]; */
83 /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
85 '?' - x[k] is missing in modified constraint
86 'L' - x[k] = (lower bound) + x'[k]
87 'U' - x[k] = (upper bound) - x'[k] */
88 /*--------------------------------------------------------------*/
89 /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
90 derived from aggregated constraint by substituting bounds;
91 note that due to substitution of variable bounds there may be
92 additional terms in the modified constraint */
93 IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */
94 /* sparse vector of modified constraint coefficients, a'[k] */
96 /* right-hand side of the modified constraint, b' */
97 /*--------------------------------------------------------------*/
98 /* cutting plane sum alpha[k] * x[k] <= beta */
99 IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */
100 /* sparse vector of cutting plane coefficients, alpha[k] */
102 /* right-hand size of the cutting plane, beta */
105 /***********************************************************************
108 * ios_mir_init - initialize MIR cut generator
112 * #include "glpios.h"
113 * void *ios_mir_init(glp_tree *tree);
117 * The routine ios_mir_init initializes the MIR cut generator assuming
118 * that the current subproblem is the root subproblem.
122 * The routine ios_mir_init returns a pointer to the MIR cut generator
125 static void set_row_attrib(glp_tree *tree, struct MIR *mir)
126 { /* set global row attributes */
127 glp_prob *mip = tree->mip;
130 for (k = 1; k <= m; k++)
131 { GLPROW *row = mip->row[k];
136 mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
138 mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
140 mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
142 mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
144 mir->lb[k] = mir->ub[k] = row->lb; break;
148 mir->vlb[k] = mir->vub[k] = 0;
153 static void set_col_attrib(glp_tree *tree, struct MIR *mir)
154 { /* set global column attributes */
155 glp_prob *mip = tree->mip;
159 for (k = m+1; k <= m+n; k++)
160 { GLPCOL *col = mip->col[k-m];
163 mir->isint[k] = 0; break;
165 mir->isint[k] = 1; break;
171 mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
173 mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
175 mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
177 mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
179 mir->lb[k] = mir->ub[k] = col->lb; break;
183 mir->vlb[k] = mir->vub[k] = 0;
188 static void set_var_bounds(glp_tree *tree, struct MIR *mir)
189 { /* set variable bounds */
190 glp_prob *mip = tree->mip;
195 for (i = 1; i <= m; i++)
196 { /* we need the row to be '>= 0' or '<= 0' */
197 if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
198 mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
199 /* take first term */
200 aij = mip->row[i]->ptr;
201 if (aij == NULL) continue;
202 k1 = m + aij->col->j, a1 = aij->val;
203 /* take second term */
205 if (aij == NULL) continue;
206 k2 = m + aij->col->j, a2 = aij->val;
207 /* there must be only two terms */
208 if (aij->r_next != NULL) continue;
209 /* interchange terms, if needed */
210 if (!mir->isint[k1] && mir->isint[k2])
212 else if (mir->isint[k1] && !mir->isint[k2])
214 k1 = m + aij->col->j, a1 = aij->val;
217 { /* both terms are either continuous or integer */
220 /* x[k2] should be double-bounded */
221 if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
222 mir->lb[k2] == mir->ub[k2]) continue;
223 /* change signs, if necessary */
224 if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
225 /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
226 is continuous, x2 is integer */
228 { /* x1 >= - (a2 / a1) * x2 */
229 if (mir->vlb[k1] == 0)
230 { /* set variable lower bound for x1 */
231 mir->lb[k1] = - a2 / a1;
233 /* the row should not be used */
238 { /* x1 <= - (a2 / a1) * x2 */
239 if (mir->vub[k1] == 0)
240 { /* set variable upper bound for x1 */
241 mir->ub[k1] = - a2 / a1;
243 /* the row should not be used */
251 static void mark_useless_rows(glp_tree *tree, struct MIR *mir)
252 { /* mark rows which should not be used */
253 glp_prob *mip = tree->mip;
257 for (i = 1; i <= m; i++)
258 { /* free rows should not be used */
259 if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
264 for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
265 { k = m + aij->col->j;
266 /* rows with free variables should not be used */
267 if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
271 /* rows with integer variables having infinite (lower or
272 upper) bound should not be used */
273 if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
274 mir->isint[k] && mir->ub[k] == +DBL_MAX)
278 /* count non-fixed variables */
279 if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
280 mir->lb[k] == mir->ub[k])) nv++;
282 /* rows with all variables fixed should not be used */
291 void *ios_mir_init(glp_tree *tree)
292 { /* initialize MIR cut generator */
293 glp_prob *mip = tree->mip;
298 xprintf("ios_mir_init: warning: debug mode enabled\n");
300 /* allocate working area */
301 mir = xmalloc(sizeof(struct MIR));
304 mir->skip = xcalloc(1+m, sizeof(char));
305 mir->isint = xcalloc(1+m+n, sizeof(char));
306 mir->lb = xcalloc(1+m+n, sizeof(double));
307 mir->vlb = xcalloc(1+m+n, sizeof(int));
308 mir->ub = xcalloc(1+m+n, sizeof(double));
309 mir->vub = xcalloc(1+m+n, sizeof(int));
310 mir->x = xcalloc(1+m+n, sizeof(double));
311 mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
312 mir->agg_vec = ios_create_vec(m+n);
313 mir->subst = xcalloc(1+m+n, sizeof(char));
314 mir->mod_vec = ios_create_vec(m+n);
315 mir->cut_vec = ios_create_vec(m+n);
316 /* set global row attributes */
317 set_row_attrib(tree, mir);
318 /* set global column attributes */
319 set_col_attrib(tree, mir);
320 /* set variable bounds */
321 set_var_bounds(tree, mir);
322 /* mark rows which should not be used */
323 mark_useless_rows(tree, mir);
327 /***********************************************************************
330 * ios_mir_gen - generate MIR cuts
334 * #include "glpios.h"
335 * void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool);
339 * The routine ios_mir_gen generates MIR cuts for the current point and
340 * adds them to the cut pool. */
342 static void get_current_point(glp_tree *tree, struct MIR *mir)
343 { /* obtain current point */
344 glp_prob *mip = tree->mip;
348 for (k = 1; k <= m; k++)
349 mir->x[k] = mip->row[k]->prim;
350 for (k = m+1; k <= m+n; k++)
351 mir->x[k] = mip->col[k-m]->prim;
356 static void check_current_point(struct MIR *mir)
357 { /* check current point */
362 for (k = 1; k <= m+n; k++)
363 { /* determine lower bound */
367 { xassert(lb != -DBL_MAX);
368 xassert(!mir->isint[k]);
369 xassert(mir->isint[kk]);
372 /* check lower bound */
374 { eps = 1e-6 * (1.0 + fabs(lb));
375 xassert(mir->x[k] >= lb - eps);
377 /* determine upper bound */
381 { xassert(ub != +DBL_MAX);
382 xassert(!mir->isint[k]);
383 xassert(mir->isint[kk]);
386 /* check upper bound */
388 { eps = 1e-6 * (1.0 + fabs(ub));
389 xassert(mir->x[k] <= ub + eps);
396 static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i)
397 { /* use original i-th row as initial aggregated constraint */
398 glp_prob *mip = tree->mip;
401 xassert(1 <= i && i <= m);
402 xassert(!mir->skip[i]);
403 /* mark i-th row in order not to use it in the same aggregated
408 /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
409 variable of row i, x[m+j] are structural variables */
410 ios_clear_vec(mir->agg_vec);
411 ios_set_vj(mir->agg_vec, i, 1.0);
412 for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
413 ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
416 ios_check_vec(mir->agg_vec);
422 static void check_agg_row(struct MIR *mir)
423 { /* check aggregated constraint */
428 /* compute the residual r = sum a[k] * x[k] - b and determine
429 big = max(1, |a[k]|, |b|) */
431 for (j = 1; j <= mir->agg_vec->nnz; j++)
432 { k = mir->agg_vec->ind[j];
433 xassert(1 <= k && k <= m+n);
434 r += mir->agg_vec->val[j] * mir->x[k];
435 if (big < fabs(mir->agg_vec->val[j]))
436 big = fabs(mir->agg_vec->val[j]);
439 if (big < fabs(mir->agg_rhs))
440 big = fabs(mir->agg_rhs);
441 /* the residual must be close to zero */
442 xassert(fabs(r) <= 1e-6 * big);
447 static void subst_fixed_vars(struct MIR *mir)
448 { /* substitute fixed variables into aggregated constraint */
452 for (j = 1; j <= mir->agg_vec->nnz; j++)
453 { k = mir->agg_vec->ind[j];
454 xassert(1 <= k && k <= m+n);
455 if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
456 mir->lb[k] == mir->ub[k])
457 { /* x[k] is fixed */
458 mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
459 mir->agg_vec->val[j] = 0.0;
462 /* remove terms corresponding to fixed variables */
463 ios_clean_vec(mir->agg_vec, DBL_EPSILON);
465 ios_check_vec(mir->agg_vec);
470 static void bound_subst_heur(struct MIR *mir)
471 { /* bound substitution heuristic */
476 for (j = 1; j <= mir->agg_vec->nnz; j++)
477 { k = mir->agg_vec->ind[j];
478 xassert(1 <= k && k <= m+n);
479 if (mir->isint[k]) continue; /* skip integer variable */
480 /* compute distance from x[k] to its lower bound */
483 { if (mir->lb[k] == -DBL_MAX)
486 d1 = mir->x[k] - mir->lb[k];
489 { xassert(1 <= kk && kk <= m+n);
490 xassert(mir->isint[kk]);
491 xassert(mir->lb[k] != -DBL_MAX);
492 d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
494 /* compute distance from x[k] to its upper bound */
497 { if (mir->vub[k] == +DBL_MAX)
500 d2 = mir->ub[k] - mir->x[k];
503 { xassert(1 <= kk && kk <= m+n);
504 xassert(mir->isint[kk]);
505 xassert(mir->ub[k] != +DBL_MAX);
506 d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
508 /* x[k] cannot be free */
509 xassert(d1 != DBL_MAX || d2 != DBL_MAX);
510 /* choose the bound which is closer to x[k] */
511 xassert(mir->subst[k] == '?');
520 static void build_mod_row(struct MIR *mir)
521 { /* substitute bounds and build modified constraint */
525 /* initially modified constraint is aggregated constraint */
526 ios_copy_vec(mir->mod_vec, mir->agg_vec);
527 mir->mod_rhs = mir->agg_rhs;
529 ios_check_vec(mir->mod_vec);
531 /* substitute bounds for continuous variables; note that due to
532 substitution of variable bounds additional terms may appear in
533 modified constraint */
534 for (j = mir->mod_vec->nnz; j >= 1; j--)
535 { k = mir->mod_vec->ind[j];
536 xassert(1 <= k && k <= m+n);
537 if (mir->isint[k]) continue; /* skip integer variable */
538 if (mir->subst[k] == 'L')
539 { /* x[k] = (lower bound) + x'[k] */
540 xassert(mir->lb[k] != -DBL_MAX);
543 { /* x[k] = lb[k] + x'[k] */
544 mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
547 { /* x[k] = lb[k] * x[kk] + x'[k] */
548 xassert(mir->isint[kk]);
549 jj = mir->mod_vec->pos[kk];
551 { ios_set_vj(mir->mod_vec, kk, 1.0);
552 jj = mir->mod_vec->pos[kk];
553 mir->mod_vec->val[jj] = 0.0;
555 mir->mod_vec->val[jj] +=
556 mir->mod_vec->val[j] * mir->lb[k];
559 else if (mir->subst[k] == 'U')
560 { /* x[k] = (upper bound) - x'[k] */
561 xassert(mir->ub[k] != +DBL_MAX);
564 { /* x[k] = ub[k] - x'[k] */
565 mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
568 { /* x[k] = ub[k] * x[kk] - x'[k] */
569 xassert(mir->isint[kk]);
570 jj = mir->mod_vec->pos[kk];
572 { ios_set_vj(mir->mod_vec, kk, 1.0);
573 jj = mir->mod_vec->pos[kk];
574 mir->mod_vec->val[jj] = 0.0;
576 mir->mod_vec->val[jj] +=
577 mir->mod_vec->val[j] * mir->ub[k];
579 mir->mod_vec->val[j] = - mir->mod_vec->val[j];
585 ios_check_vec(mir->mod_vec);
587 /* substitute bounds for integer variables */
588 for (j = 1; j <= mir->mod_vec->nnz; j++)
589 { k = mir->mod_vec->ind[j];
590 xassert(1 <= k && k <= m+n);
591 if (!mir->isint[k]) continue; /* skip continuous variable */
592 xassert(mir->subst[k] == '?');
593 xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
594 xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
595 if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
596 { /* x[k] = lb[k] + x'[k] */
598 mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
601 { /* x[k] = ub[k] - x'[k] */
603 mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
604 mir->mod_vec->val[j] = - mir->mod_vec->val[j];
608 ios_check_vec(mir->mod_vec);
614 static void check_mod_row(struct MIR *mir)
615 { /* check modified constraint */
620 /* compute the residual r = sum a'[k] * x'[k] - b' and determine
621 big = max(1, |a[k]|, |b|) */
623 for (j = 1; j <= mir->mod_vec->nnz; j++)
624 { k = mir->mod_vec->ind[j];
625 xassert(1 <= k && k <= m+n);
626 if (mir->subst[k] == 'L')
627 { /* x'[k] = x[k] - (lower bound) */
628 xassert(mir->lb[k] != -DBL_MAX);
631 x = mir->x[k] - mir->lb[k];
633 x = mir->x[k] - mir->lb[k] * mir->x[kk];
635 else if (mir->subst[k] == 'U')
636 { /* x'[k] = (upper bound) - x[k] */
637 xassert(mir->ub[k] != +DBL_MAX);
640 x = mir->ub[k] - mir->x[k];
642 x = mir->ub[k] * mir->x[kk] - mir->x[k];
646 r += mir->mod_vec->val[j] * x;
647 if (big < fabs(mir->mod_vec->val[j]))
648 big = fabs(mir->mod_vec->val[j]);
651 if (big < fabs(mir->mod_rhs))
652 big = fabs(mir->mod_rhs);
653 /* the residual must be close to zero */
654 xassert(fabs(r) <= 1e-6 * big);
659 /***********************************************************************
660 * mir_ineq - construct MIR inequality
662 * Given the single constraint mixed integer set
665 * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s},
668 * this routine constructs the mixed integer rounding (MIR) inequality
670 * sum alpha[j] * x[j] <= beta + gamma * s,
673 * which is valid for X.
675 * If the MIR inequality has been successfully constructed, the routine
676 * returns zero. Otherwise, if b is close to nearest integer, there may
677 * be numeric difficulties due to big coefficients; so in this case the
678 * routine returns non-zero. */
680 static int mir_ineq(const int n, const double a[], const double b,
681 double alpha[], double *beta, double *gamma)
684 if (fabs(b - floor(b + .5)) < 0.01)
687 for (j = 1; j <= n; j++)
688 { t = (a[j] - floor(a[j])) - f;
690 alpha[j] = floor(a[j]);
692 alpha[j] = floor(a[j]) + t / (1.0 - f);
695 *gamma = 1.0 / (1.0 - f);
699 /***********************************************************************
700 * cmir_ineq - construct c-MIR inequality
702 * Given the mixed knapsack set
705 * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
710 * a subset C of variables to be complemented, and a divisor delta > 0,
711 * this routine constructs the complemented MIR (c-MIR) inequality
713 * sum alpha[j] * x[j] <= beta + gamma * s,
716 * which is valid for X .
718 * If the c-MIR inequality has been successfully constructed, the
719 * routine returns zero. Otherwise, if there is a risk of numerical
720 * difficulties due to big coefficients (see comments to the routine
721 * mir_ineq), the routine cmir_ineq returns non-zero. */
723 static int cmir_ineq(const int n, const double a[], const double b,
724 const double u[], const char cset[], const double delta,
725 double alpha[], double *beta, double *gamma)
729 for (j = 1; j <= n; j++)
730 { aa[j] = a[j] / delta;
732 aa[j] = - aa[j], bb -= a[j] * u[j];
735 if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
736 for (j = 1; j <= n; j++)
738 alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
744 /***********************************************************************
745 * cmir_sep - c-MIR separation heuristic
747 * Given the mixed knapsack set
750 * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
756 * and a fractional point (x , s ), this routine tries to construct
759 * sum alpha[j] * x[j] <= beta + gamma * s,
762 * which is valid for X and has (desirably maximal) violation at the
763 * fractional point given. This is attained by choosing an appropriate
764 * set C of variables to be complemented and a divisor delta > 0, which
765 * together define corresponding c-MIR inequality.
767 * If a violated c-MIR inequality has been successfully constructed,
768 * the routine returns its violation:
771 * sum alpha[j] * x [j] - beta - gamma * s ,
774 * which is positive. In case of failure the routine returns zero. */
776 struct vset { int j; double v; };
778 static int cmir_cmp(const void *p1, const void *p2)
779 { const struct vset *v1 = p1, *v2 = p2;
780 if (v1->v < v2->v) return -1;
781 if (v1->v > v2->v) return +1;
785 static double cmir_sep(const int n, const double a[], const double b,
786 const double u[], const double x[], const double s,
787 double alpha[], double *beta, double *gamma)
788 { int fail, j, k, nv, v;
789 double delta, eps, d_try[1+3], r, r_best;
792 /* allocate working arrays */
793 cset = xcalloc(1+n, sizeof(char));
794 vset = xcalloc(1+n, sizeof(struct vset));
795 /* choose initial C */
796 for (j = 1; j <= n; j++)
797 cset[j] = (char)(x[j] >= 0.5 * u[j]);
798 /* choose initial delta */
799 r_best = delta = 0.0;
800 for (j = 1; j <= n; j++)
801 { xassert(a[j] != 0.0);
802 /* if x[j] is close to its bounds, skip it */
803 eps = 1e-9 * (1.0 + fabs(u[j]));
804 if (x[j] < eps || x[j] > u[j] - eps) continue;
805 /* try delta = |a[j]| to construct c-MIR inequality */
806 fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
809 /* compute violation */
810 r = - (*beta) - (*gamma) * s;
811 for (k = 1; k <= n; k++) r += alpha[k] * x[k];
812 if (r_best < r) r_best = r, delta = fabs(a[j]);
814 if (r_best < 0.001) r_best = 0.0;
815 if (r_best == 0.0) goto done;
816 xassert(delta > 0.0);
817 /* try to increase violation by dividing delta by 2, 4, and 8,
819 d_try[1] = delta / 2.0;
820 d_try[2] = delta / 4.0;
821 d_try[3] = delta / 8.0;
822 for (j = 1; j <= 3; j++)
823 { /* construct c-MIR inequality */
824 fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
827 /* compute violation */
828 r = - (*beta) - (*gamma) * s;
829 for (k = 1; k <= n; k++) r += alpha[k] * x[k];
830 if (r_best < r) r_best = r, delta = d_try[j];
832 /* build subset of variables lying strictly between their bounds
833 and order it by nondecreasing values of |x[j] - u[j]/2| */
835 for (j = 1; j <= n; j++)
836 { /* if x[j] is close to its bounds, skip it */
837 eps = 1e-9 * (1.0 + fabs(u[j]));
838 if (x[j] < eps || x[j] > u[j] - eps) continue;
839 /* add x[j] to the subset */
842 vset[nv].v = fabs(x[j] - 0.5 * u[j]);
844 qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
845 /* try to increase violation by successively complementing each
846 variable in the subset */
847 for (v = 1; v <= nv; v++)
849 /* replace x[j] by its complement or vice versa */
850 cset[j] = (char)!cset[j];
851 /* construct c-MIR inequality */
852 fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
853 /* restore the variable */
854 cset[j] = (char)!cset[j];
855 /* do not replace the variable in case of failure */
857 /* compute violation */
858 r = - (*beta) - (*gamma) * s;
859 for (k = 1; k <= n; k++) r += alpha[k] * x[k];
860 if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
862 /* construct the best c-MIR inequality chosen */
863 fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
865 done: /* free working arrays */
868 /* return to the calling routine */
872 static double generate(struct MIR *mir)
873 { /* try to generate violated c-MIR cut for modified constraint */
877 double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
878 ios_copy_vec(mir->cut_vec, mir->mod_vec);
879 mir->cut_rhs = mir->mod_rhs;
880 /* remove small terms, which can appear due to substitution of
882 ios_clean_vec(mir->cut_vec, DBL_EPSILON);
884 ios_check_vec(mir->cut_vec);
886 /* remove positive continuous terms to obtain MK relaxation */
887 for (j = 1; j <= mir->cut_vec->nnz; j++)
888 { k = mir->cut_vec->ind[j];
889 xassert(1 <= k && k <= m+n);
890 if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
891 mir->cut_vec->val[j] = 0.0;
893 ios_clean_vec(mir->cut_vec, 0.0);
895 ios_check_vec(mir->cut_vec);
897 /* move integer terms to the beginning of the sparse vector and
898 determine the number of integer variables */
900 for (j = 1; j <= mir->cut_vec->nnz; j++)
901 { k = mir->cut_vec->ind[j];
902 xassert(1 <= k && k <= m+n);
906 /* interchange elements [nint] and [j] */
907 kk = mir->cut_vec->ind[nint];
908 mir->cut_vec->pos[k] = nint;
909 mir->cut_vec->pos[kk] = j;
910 mir->cut_vec->ind[nint] = k;
911 mir->cut_vec->ind[j] = kk;
912 temp = mir->cut_vec->val[nint];
913 mir->cut_vec->val[nint] = mir->cut_vec->val[j];
914 mir->cut_vec->val[j] = temp;
918 ios_check_vec(mir->cut_vec);
920 /* if there is no integer variable, nothing to generate */
921 if (nint == 0) goto done;
922 /* allocate working arrays */
923 u = xcalloc(1+nint, sizeof(double));
924 x = xcalloc(1+nint, sizeof(double));
925 alpha = xcalloc(1+nint, sizeof(double));
926 /* determine u and x */
927 for (j = 1; j <= nint; j++)
928 { k = mir->cut_vec->ind[j];
929 xassert(m+1 <= k && k <= m+n);
930 xassert(mir->isint[k]);
931 u[j] = mir->ub[k] - mir->lb[k];
932 xassert(u[j] >= 1.0);
933 if (mir->subst[k] == 'L')
934 x[j] = mir->x[k] - mir->lb[k];
935 else if (mir->subst[k] == 'U')
936 x[j] = mir->ub[k] - mir->x[k];
939 xassert(x[j] >= -0.001);
940 if (x[j] < 0.0) x[j] = 0.0;
942 /* compute s = - sum of continuous terms */
944 for (j = nint+1; j <= mir->cut_vec->nnz; j++)
946 k = mir->cut_vec->ind[j];
947 xassert(1 <= k && k <= m+n);
948 /* must be continuous */
949 xassert(!mir->isint[k]);
950 if (mir->subst[k] == 'L')
951 { xassert(mir->lb[k] != -DBL_MAX);
954 x = mir->x[k] - mir->lb[k];
956 x = mir->x[k] - mir->lb[k] * mir->x[kk];
958 else if (mir->subst[k] == 'U')
959 { xassert(mir->ub[k] != +DBL_MAX);
962 x = mir->ub[k] - mir->x[k];
964 x = mir->ub[k] * mir->x[kk] - mir->x[k];
968 xassert(x >= -0.001);
969 if (x < 0.0) x = 0.0;
970 s -= mir->cut_vec->val[j] * x;
973 /* apply heuristic to obtain most violated c-MIR inequality */
975 r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
977 if (r_best == 0.0) goto skip;
978 xassert(r_best > 0.0);
979 /* convert to raw cut */
980 /* sum alpha[j] * x[j] <= beta + gamma * s */
981 for (j = 1; j <= nint; j++)
982 mir->cut_vec->val[j] = alpha[j];
983 for (j = nint+1; j <= mir->cut_vec->nnz; j++)
984 { k = mir->cut_vec->ind[j];
985 if (k <= m+n) mir->cut_vec->val[j] *= gamma;
989 ios_check_vec(mir->cut_vec);
991 skip: /* free working arrays */
999 static void check_raw_cut(struct MIR *mir, double r_best)
1000 { /* check raw cut before back bound substitution */
1005 /* compute the residual r = sum a[k] * x[k] - b and determine
1006 big = max(1, |a[k]|, |b|) */
1008 for (j = 1; j <= mir->cut_vec->nnz; j++)
1009 { k = mir->cut_vec->ind[j];
1010 xassert(1 <= k && k <= m+n);
1011 if (mir->subst[k] == 'L')
1012 { xassert(mir->lb[k] != -DBL_MAX);
1015 x = mir->x[k] - mir->lb[k];
1017 x = mir->x[k] - mir->lb[k] * mir->x[kk];
1019 else if (mir->subst[k] == 'U')
1020 { xassert(mir->ub[k] != +DBL_MAX);
1023 x = mir->ub[k] - mir->x[k];
1025 x = mir->ub[k] * mir->x[kk] - mir->x[k];
1029 r += mir->cut_vec->val[j] * x;
1030 if (big < fabs(mir->cut_vec->val[j]))
1031 big = fabs(mir->cut_vec->val[j]);
1034 if (big < fabs(mir->cut_rhs))
1035 big = fabs(mir->cut_rhs);
1036 /* the residual must be close to r_best */
1037 xassert(fabs(r - r_best) <= 1e-6 * big);
1042 static void back_subst(struct MIR *mir)
1043 { /* back substitution of original bounds */
1047 /* at first, restore bounds of integer variables (because on
1048 restoring variable bounds of continuous variables we need
1049 original, not shifted, bounds of integer variables) */
1050 for (j = 1; j <= mir->cut_vec->nnz; j++)
1051 { k = mir->cut_vec->ind[j];
1052 xassert(1 <= k && k <= m+n);
1053 if (!mir->isint[k]) continue; /* skip continuous */
1054 if (mir->subst[k] == 'L')
1055 { /* x'[k] = x[k] - lb[k] */
1056 xassert(mir->lb[k] != -DBL_MAX);
1057 xassert(mir->vlb[k] == 0);
1058 mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
1060 else if (mir->subst[k] == 'U')
1061 { /* x'[k] = ub[k] - x[k] */
1062 xassert(mir->ub[k] != +DBL_MAX);
1063 xassert(mir->vub[k] == 0);
1064 mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
1065 mir->cut_vec->val[j] = - mir->cut_vec->val[j];
1070 /* now restore bounds of continuous variables */
1071 for (j = 1; j <= mir->cut_vec->nnz; j++)
1072 { k = mir->cut_vec->ind[j];
1073 xassert(1 <= k && k <= m+n);
1074 if (mir->isint[k]) continue; /* skip integer */
1075 if (mir->subst[k] == 'L')
1076 { /* x'[k] = x[k] - (lower bound) */
1077 xassert(mir->lb[k] != -DBL_MAX);
1080 { /* x'[k] = x[k] - lb[k] */
1081 mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
1084 { /* x'[k] = x[k] - lb[k] * x[kk] */
1085 jj = mir->cut_vec->pos[kk];
1090 { ios_set_vj(mir->cut_vec, kk, 1.0);
1091 jj = mir->cut_vec->pos[kk];
1093 mir->cut_vec->val[jj] = 0.0;
1096 mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
1100 else if (mir->subst[k] == 'U')
1101 { /* x'[k] = (upper bound) - x[k] */
1102 xassert(mir->ub[k] != +DBL_MAX);
1105 { /* x'[k] = ub[k] - x[k] */
1106 mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
1109 { /* x'[k] = ub[k] * x[kk] - x[k] */
1110 jj = mir->cut_vec->pos[kk];
1112 { ios_set_vj(mir->cut_vec, kk, 1.0);
1113 jj = mir->cut_vec->pos[kk];
1115 mir->cut_vec->val[jj] = 0.0;
1117 mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
1120 mir->cut_vec->val[j] = - mir->cut_vec->val[j];
1126 ios_check_vec(mir->cut_vec);
1132 static void check_cut_row(struct MIR *mir, double r_best)
1133 { /* check the cut after back bound substitution or elimination of
1134 auxiliary variables */
1139 /* compute the residual r = sum a[k] * x[k] - b and determine
1140 big = max(1, |a[k]|, |b|) */
1142 for (j = 1; j <= mir->cut_vec->nnz; j++)
1143 { k = mir->cut_vec->ind[j];
1144 xassert(1 <= k && k <= m+n);
1145 r += mir->cut_vec->val[j] * mir->x[k];
1146 if (big < fabs(mir->cut_vec->val[j]))
1147 big = fabs(mir->cut_vec->val[j]);
1150 if (big < fabs(mir->cut_rhs))
1151 big = fabs(mir->cut_rhs);
1152 /* the residual must be close to r_best */
1153 xassert(fabs(r - r_best) <= 1e-6 * big);
1158 static void subst_aux_vars(glp_tree *tree, struct MIR *mir)
1159 { /* final substitution to eliminate auxiliary variables */
1160 glp_prob *mip = tree->mip;
1165 for (j = mir->cut_vec->nnz; j >= 1; j--)
1166 { k = mir->cut_vec->ind[j];
1167 xassert(1 <= k && k <= m+n);
1168 if (k > m) continue; /* skip structurals */
1169 for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
1170 { kk = m + aij->col->j; /* structural */
1171 jj = mir->cut_vec->pos[kk];
1173 { ios_set_vj(mir->cut_vec, kk, 1.0);
1174 jj = mir->cut_vec->pos[kk];
1175 mir->cut_vec->val[jj] = 0.0;
1177 mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
1179 mir->cut_vec->val[j] = 0.0;
1181 ios_clean_vec(mir->cut_vec, 0.0);
1185 static void add_cut(glp_tree *tree, struct MIR *mir)
1186 { /* add constructed cut inequality to the cut pool */
1190 int *ind = xcalloc(1+n, sizeof(int));
1191 double *val = xcalloc(1+n, sizeof(double));
1193 for (j = mir->cut_vec->nnz; j >= 1; j--)
1194 { k = mir->cut_vec->ind[j];
1195 xassert(m+1 <= k && k <= m+n);
1196 len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
1199 ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
1202 glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
1210 static int aggregate_row(glp_tree *tree, struct MIR *mir)
1211 { /* try to aggregate another row */
1212 glp_prob *mip = tree->mip;
1217 int ii, j, jj, k, kk, kappa = 0, ret = 0;
1218 double d1, d2, d, d_max = 0.0;
1219 /* choose appropriate structural variable in the aggregated row
1220 to be substituted */
1221 for (j = 1; j <= mir->agg_vec->nnz; j++)
1222 { k = mir->agg_vec->ind[j];
1223 xassert(1 <= k && k <= m+n);
1224 if (k <= m) continue; /* skip auxiliary var */
1225 if (mir->isint[k]) continue; /* skip integer var */
1226 if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
1227 /* compute distance from x[k] to its lower bound */
1230 { if (mir->lb[k] == -DBL_MAX)
1233 d1 = mir->x[k] - mir->lb[k];
1236 { xassert(1 <= kk && kk <= m+n);
1237 xassert(mir->isint[kk]);
1238 xassert(mir->lb[k] != -DBL_MAX);
1239 d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
1241 /* compute distance from x[k] to its upper bound */
1244 { if (mir->vub[k] == +DBL_MAX)
1247 d2 = mir->ub[k] - mir->x[k];
1250 { xassert(1 <= kk && kk <= m+n);
1251 xassert(mir->isint[kk]);
1252 xassert(mir->ub[k] != +DBL_MAX);
1253 d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
1255 /* x[k] cannot be free */
1256 xassert(d1 != DBL_MAX || d2 != DBL_MAX);
1257 /* d = min(d1, d2) */
1258 d = (d1 <= d2 ? d1 : d2);
1259 xassert(d != DBL_MAX);
1260 /* should not be close to corresponding bound */
1261 if (d < 0.001) continue;
1262 if (d_max < d) d_max = d, kappa = k;
1265 { /* nothing chosen */
1269 /* x[kappa] has been chosen */
1270 xassert(m+1 <= kappa && kappa <= m+n);
1271 xassert(!mir->isint[kappa]);
1272 /* find another row, which have not been used yet, to eliminate
1273 x[kappa] from the aggregated row */
1274 for (ii = 1; ii <= m; ii++)
1275 { if (mir->skip[ii]) continue;
1276 for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
1277 if (aij->col->j == kappa - m) break;
1278 if (aij != NULL && fabs(aij->val) >= 0.001) break;
1281 { /* nothing found */
1285 /* row ii has been found; include it in the aggregated list */
1287 xassert(mir->agg_cnt <= MAXAGGR);
1288 mir->agg_row[mir->agg_cnt] = ii;
1291 v = ios_create_vec(m+n);
1292 ios_set_vj(v, ii, 1.0);
1293 for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
1294 ios_set_vj(v, m + aij->col->j, - aij->val);
1298 /* perform gaussian elimination to remove x[kappa] */
1299 j = mir->agg_vec->pos[kappa];
1303 ios_linear_comb(mir->agg_vec,
1304 - mir->agg_vec->val[j] / v->val[jj], v);
1306 ios_set_vj(mir->agg_vec, kappa, 0.0);
1308 ios_check_vec(mir->agg_vec);
1313 void ios_mir_gen(glp_tree *tree, void *gen)
1314 { /* main routine to generate MIR cuts */
1315 glp_prob *mip = tree->mip;
1316 struct MIR *mir = gen;
1321 xassert(mip->m >= m);
1322 xassert(mip->n == n);
1323 /* obtain current point */
1324 get_current_point(tree, mir);
1326 /* check current point */
1327 check_current_point(mir);
1329 /* reset bound substitution flags */
1330 memset(&mir->subst[1], '?', m+n);
1331 /* try to generate a set of violated MIR cuts */
1332 for (i = 1; i <= m; i++)
1333 { if (mir->skip[i]) continue;
1334 /* use original i-th row as initial aggregated constraint */
1335 initial_agg_row(tree, mir, i);
1338 /* check aggregated row */
1341 /* substitute fixed variables into aggregated constraint */
1342 subst_fixed_vars(mir);
1344 /* check aggregated row */
1348 /* check bound substitution flags */
1350 for (k = 1; k <= m+n; k++)
1351 xassert(mir->subst[k] == '?');
1354 /* apply bound substitution heuristic */
1355 bound_subst_heur(mir);
1356 /* substitute bounds and build modified constraint */
1359 /* check modified row */
1362 /* try to generate violated c-MIR cut for modified row */
1363 r_best = generate(mir);
1367 /* check raw cut before back bound substitution */
1368 check_raw_cut(mir, r_best);
1370 /* back substitution of original bounds */
1373 /* check the cut after back bound substitution */
1374 check_cut_row(mir, r_best);
1376 /* final substitution to eliminate auxiliary variables */
1377 subst_aux_vars(tree, mir);
1379 /* check the cut after elimination of auxiliaries */
1380 check_cut_row(mir, r_best);
1382 /* add constructed cut inequality to the cut pool */
1385 /* reset bound substitution flags */
1387 for (j = 1; j <= mir->mod_vec->nnz; j++)
1388 { k = mir->mod_vec->ind[j];
1389 xassert(1 <= k && k <= m+n);
1390 xassert(mir->subst[k] != '?');
1391 mir->subst[k] = '?';
1396 if (mir->agg_cnt < MAXAGGR)
1397 { /* try to aggregate another row */
1398 if (aggregate_row(tree, mir) == 0) goto loop;
1401 /* unmark rows used in the aggregated constraint */
1403 for (k = 1; k <= mir->agg_cnt; k++)
1404 { ii = mir->agg_row[k];
1405 xassert(1 <= ii && ii <= m);
1406 xassert(mir->skip[ii] == 2);
1414 /***********************************************************************
1417 * ios_mir_term - terminate MIR cut generator
1421 * #include "glpios.h"
1422 * void ios_mir_term(void *gen);
1426 * The routine ios_mir_term deletes the MIR cut generator working area
1427 * freeing all the memory allocated to it. */
1429 void ios_mir_term(void *gen)
1430 { struct MIR *mir = gen;
1438 xfree(mir->agg_row);
1439 ios_delete_vec(mir->agg_vec);
1441 ios_delete_vec(mir->mod_vec);
1442 ios_delete_vec(mir->cut_vec);