[1] | 1 | /* glpios06.c (MIR cut generator) */ |
---|
| 2 | |
---|
| 3 | /*********************************************************************** |
---|
| 4 | * This code is part of GLPK (GNU Linear Programming Kit). |
---|
| 5 | * |
---|
| 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>. |
---|
| 10 | * |
---|
| 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. |
---|
| 15 | * |
---|
| 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. |
---|
| 20 | * |
---|
| 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 | ***********************************************************************/ |
---|
| 24 | |
---|
| 25 | #include "glpios.h" |
---|
| 26 | |
---|
| 27 | #define _MIR_DEBUG 0 |
---|
| 28 | |
---|
| 29 | #define MAXAGGR 5 |
---|
| 30 | /* maximal number of rows which can be aggregated */ |
---|
| 31 | |
---|
| 32 | struct MIR |
---|
| 33 | { /* MIR cut generator working area */ |
---|
| 34 | /*--------------------------------------------------------------*/ |
---|
| 35 | /* global information valid for the root subproblem */ |
---|
| 36 | int m; |
---|
| 37 | /* number of rows (in the root subproblem) */ |
---|
| 38 | int n; |
---|
| 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 */ |
---|
| 70 | int agg_cnt; |
---|
| 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] */ |
---|
| 78 | double agg_rhs; |
---|
| 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 |
---|
| 84 | variable x[k]: |
---|
| 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] */ |
---|
| 95 | double mod_rhs; |
---|
| 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] */ |
---|
| 101 | double cut_rhs; |
---|
| 102 | /* right-hand size of the cutting plane, beta */ |
---|
| 103 | }; |
---|
| 104 | |
---|
| 105 | /*********************************************************************** |
---|
| 106 | * NAME |
---|
| 107 | * |
---|
| 108 | * ios_mir_init - initialize MIR cut generator |
---|
| 109 | * |
---|
| 110 | * SYNOPSIS |
---|
| 111 | * |
---|
| 112 | * #include "glpios.h" |
---|
| 113 | * void *ios_mir_init(glp_tree *tree); |
---|
| 114 | * |
---|
| 115 | * DESCRIPTION |
---|
| 116 | * |
---|
| 117 | * The routine ios_mir_init initializes the MIR cut generator assuming |
---|
| 118 | * that the current subproblem is the root subproblem. |
---|
| 119 | * |
---|
| 120 | * RETURNS |
---|
| 121 | * |
---|
| 122 | * The routine ios_mir_init returns a pointer to the MIR cut generator |
---|
| 123 | * working area. */ |
---|
| 124 | |
---|
| 125 | static void set_row_attrib(glp_tree *tree, struct MIR *mir) |
---|
| 126 | { /* set global row attributes */ |
---|
| 127 | glp_prob *mip = tree->mip; |
---|
| 128 | int m = mir->m; |
---|
| 129 | int k; |
---|
| 130 | for (k = 1; k <= m; k++) |
---|
| 131 | { GLPROW *row = mip->row[k]; |
---|
| 132 | mir->skip[k] = 0; |
---|
| 133 | mir->isint[k] = 0; |
---|
| 134 | switch (row->type) |
---|
| 135 | { case GLP_FR: |
---|
| 136 | mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break; |
---|
| 137 | case GLP_LO: |
---|
| 138 | mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break; |
---|
| 139 | case GLP_UP: |
---|
| 140 | mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break; |
---|
| 141 | case GLP_DB: |
---|
| 142 | mir->lb[k] = row->lb, mir->ub[k] = row->ub; break; |
---|
| 143 | case GLP_FX: |
---|
| 144 | mir->lb[k] = mir->ub[k] = row->lb; break; |
---|
| 145 | default: |
---|
| 146 | xassert(row != row); |
---|
| 147 | } |
---|
| 148 | mir->vlb[k] = mir->vub[k] = 0; |
---|
| 149 | } |
---|
| 150 | return; |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | static void set_col_attrib(glp_tree *tree, struct MIR *mir) |
---|
| 154 | { /* set global column attributes */ |
---|
| 155 | glp_prob *mip = tree->mip; |
---|
| 156 | int m = mir->m; |
---|
| 157 | int n = mir->n; |
---|
| 158 | int k; |
---|
| 159 | for (k = m+1; k <= m+n; k++) |
---|
| 160 | { GLPCOL *col = mip->col[k-m]; |
---|
| 161 | switch (col->kind) |
---|
| 162 | { case GLP_CV: |
---|
| 163 | mir->isint[k] = 0; break; |
---|
| 164 | case GLP_IV: |
---|
| 165 | mir->isint[k] = 1; break; |
---|
| 166 | default: |
---|
| 167 | xassert(col != col); |
---|
| 168 | } |
---|
| 169 | switch (col->type) |
---|
| 170 | { case GLP_FR: |
---|
| 171 | mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break; |
---|
| 172 | case GLP_LO: |
---|
| 173 | mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break; |
---|
| 174 | case GLP_UP: |
---|
| 175 | mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break; |
---|
| 176 | case GLP_DB: |
---|
| 177 | mir->lb[k] = col->lb, mir->ub[k] = col->ub; break; |
---|
| 178 | case GLP_FX: |
---|
| 179 | mir->lb[k] = mir->ub[k] = col->lb; break; |
---|
| 180 | default: |
---|
| 181 | xassert(col != col); |
---|
| 182 | } |
---|
| 183 | mir->vlb[k] = mir->vub[k] = 0; |
---|
| 184 | } |
---|
| 185 | return; |
---|
| 186 | } |
---|
| 187 | |
---|
| 188 | static void set_var_bounds(glp_tree *tree, struct MIR *mir) |
---|
| 189 | { /* set variable bounds */ |
---|
| 190 | glp_prob *mip = tree->mip; |
---|
| 191 | int m = mir->m; |
---|
| 192 | GLPAIJ *aij; |
---|
| 193 | int i, k1, k2; |
---|
| 194 | double a1, a2; |
---|
| 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 */ |
---|
| 204 | aij = aij->r_next; |
---|
| 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]) |
---|
| 211 | ; |
---|
| 212 | else if (mir->isint[k1] && !mir->isint[k2]) |
---|
| 213 | { k2 = k1, a2 = a1; |
---|
| 214 | k1 = m + aij->col->j, a1 = aij->val; |
---|
| 215 | } |
---|
| 216 | else |
---|
| 217 | { /* both terms are either continuous or integer */ |
---|
| 218 | continue; |
---|
| 219 | } |
---|
| 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 */ |
---|
| 227 | if (a1 > 0.0) |
---|
| 228 | { /* x1 >= - (a2 / a1) * x2 */ |
---|
| 229 | if (mir->vlb[k1] == 0) |
---|
| 230 | { /* set variable lower bound for x1 */ |
---|
| 231 | mir->lb[k1] = - a2 / a1; |
---|
| 232 | mir->vlb[k1] = k2; |
---|
| 233 | /* the row should not be used */ |
---|
| 234 | mir->skip[i] = 1; |
---|
| 235 | } |
---|
| 236 | } |
---|
| 237 | else /* a1 < 0.0 */ |
---|
| 238 | { /* x1 <= - (a2 / a1) * x2 */ |
---|
| 239 | if (mir->vub[k1] == 0) |
---|
| 240 | { /* set variable upper bound for x1 */ |
---|
| 241 | mir->ub[k1] = - a2 / a1; |
---|
| 242 | mir->vub[k1] = k2; |
---|
| 243 | /* the row should not be used */ |
---|
| 244 | mir->skip[i] = 1; |
---|
| 245 | } |
---|
| 246 | } |
---|
| 247 | } |
---|
| 248 | return; |
---|
| 249 | } |
---|
| 250 | |
---|
| 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; |
---|
| 254 | int m = mir->m; |
---|
| 255 | GLPAIJ *aij; |
---|
| 256 | int i, k, nv; |
---|
| 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) |
---|
| 260 | { mir->skip[i] = 1; |
---|
| 261 | continue; |
---|
| 262 | } |
---|
| 263 | nv = 0; |
---|
| 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) |
---|
| 268 | { mir->skip[i] = 1; |
---|
| 269 | break; |
---|
| 270 | } |
---|
| 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) |
---|
| 275 | { mir->skip[i] = 1; |
---|
| 276 | break; |
---|
| 277 | } |
---|
| 278 | /* count non-fixed variables */ |
---|
| 279 | if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 && |
---|
| 280 | mir->lb[k] == mir->ub[k])) nv++; |
---|
| 281 | } |
---|
| 282 | /* rows with all variables fixed should not be used */ |
---|
| 283 | if (nv == 0) |
---|
| 284 | { mir->skip[i] = 1; |
---|
| 285 | continue; |
---|
| 286 | } |
---|
| 287 | } |
---|
| 288 | return; |
---|
| 289 | } |
---|
| 290 | |
---|
| 291 | void *ios_mir_init(glp_tree *tree) |
---|
| 292 | { /* initialize MIR cut generator */ |
---|
| 293 | glp_prob *mip = tree->mip; |
---|
| 294 | int m = mip->m; |
---|
| 295 | int n = mip->n; |
---|
| 296 | struct MIR *mir; |
---|
| 297 | #if _MIR_DEBUG |
---|
| 298 | xprintf("ios_mir_init: warning: debug mode enabled\n"); |
---|
| 299 | #endif |
---|
| 300 | /* allocate working area */ |
---|
| 301 | mir = xmalloc(sizeof(struct MIR)); |
---|
| 302 | mir->m = m; |
---|
| 303 | mir->n = n; |
---|
| 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); |
---|
| 324 | return mir; |
---|
| 325 | } |
---|
| 326 | |
---|
| 327 | /*********************************************************************** |
---|
| 328 | * NAME |
---|
| 329 | * |
---|
| 330 | * ios_mir_gen - generate MIR cuts |
---|
| 331 | * |
---|
| 332 | * SYNOPSIS |
---|
| 333 | * |
---|
| 334 | * #include "glpios.h" |
---|
| 335 | * void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool); |
---|
| 336 | * |
---|
| 337 | * DESCRIPTION |
---|
| 338 | * |
---|
| 339 | * The routine ios_mir_gen generates MIR cuts for the current point and |
---|
| 340 | * adds them to the cut pool. */ |
---|
| 341 | |
---|
| 342 | static void get_current_point(glp_tree *tree, struct MIR *mir) |
---|
| 343 | { /* obtain current point */ |
---|
| 344 | glp_prob *mip = tree->mip; |
---|
| 345 | int m = mir->m; |
---|
| 346 | int n = mir->n; |
---|
| 347 | int k; |
---|
| 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; |
---|
| 352 | return; |
---|
| 353 | } |
---|
| 354 | |
---|
| 355 | #if _MIR_DEBUG |
---|
| 356 | static void check_current_point(struct MIR *mir) |
---|
| 357 | { /* check current point */ |
---|
| 358 | int m = mir->m; |
---|
| 359 | int n = mir->n; |
---|
| 360 | int k, kk; |
---|
| 361 | double lb, ub, eps; |
---|
| 362 | for (k = 1; k <= m+n; k++) |
---|
| 363 | { /* determine lower bound */ |
---|
| 364 | lb = mir->lb[k]; |
---|
| 365 | kk = mir->vlb[k]; |
---|
| 366 | if (kk != 0) |
---|
| 367 | { xassert(lb != -DBL_MAX); |
---|
| 368 | xassert(!mir->isint[k]); |
---|
| 369 | xassert(mir->isint[kk]); |
---|
| 370 | lb *= mir->x[kk]; |
---|
| 371 | } |
---|
| 372 | /* check lower bound */ |
---|
| 373 | if (lb != -DBL_MAX) |
---|
| 374 | { eps = 1e-6 * (1.0 + fabs(lb)); |
---|
| 375 | xassert(mir->x[k] >= lb - eps); |
---|
| 376 | } |
---|
| 377 | /* determine upper bound */ |
---|
| 378 | ub = mir->ub[k]; |
---|
| 379 | kk = mir->vub[k]; |
---|
| 380 | if (kk != 0) |
---|
| 381 | { xassert(ub != +DBL_MAX); |
---|
| 382 | xassert(!mir->isint[k]); |
---|
| 383 | xassert(mir->isint[kk]); |
---|
| 384 | ub *= mir->x[kk]; |
---|
| 385 | } |
---|
| 386 | /* check upper bound */ |
---|
| 387 | if (ub != +DBL_MAX) |
---|
| 388 | { eps = 1e-6 * (1.0 + fabs(ub)); |
---|
| 389 | xassert(mir->x[k] <= ub + eps); |
---|
| 390 | } |
---|
| 391 | } |
---|
| 392 | return; |
---|
| 393 | } |
---|
| 394 | #endif |
---|
| 395 | |
---|
| 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; |
---|
| 399 | int m = mir->m; |
---|
| 400 | GLPAIJ *aij; |
---|
| 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 |
---|
| 404 | constraint */ |
---|
| 405 | mir->skip[i] = 2; |
---|
| 406 | mir->agg_cnt = 1; |
---|
| 407 | mir->agg_row[1] = i; |
---|
| 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); |
---|
| 414 | mir->agg_rhs = 0.0; |
---|
| 415 | #if _MIR_DEBUG |
---|
| 416 | ios_check_vec(mir->agg_vec); |
---|
| 417 | #endif |
---|
| 418 | return; |
---|
| 419 | } |
---|
| 420 | |
---|
| 421 | #if _MIR_DEBUG |
---|
| 422 | static void check_agg_row(struct MIR *mir) |
---|
| 423 | { /* check aggregated constraint */ |
---|
| 424 | int m = mir->m; |
---|
| 425 | int n = mir->n; |
---|
| 426 | int j, k; |
---|
| 427 | double r, big; |
---|
| 428 | /* compute the residual r = sum a[k] * x[k] - b and determine |
---|
| 429 | big = max(1, |a[k]|, |b|) */ |
---|
| 430 | r = 0.0, big = 1.0; |
---|
| 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]); |
---|
| 437 | } |
---|
| 438 | r -= mir->agg_rhs; |
---|
| 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); |
---|
| 443 | return; |
---|
| 444 | } |
---|
| 445 | #endif |
---|
| 446 | |
---|
| 447 | static void subst_fixed_vars(struct MIR *mir) |
---|
| 448 | { /* substitute fixed variables into aggregated constraint */ |
---|
| 449 | int m = mir->m; |
---|
| 450 | int n = mir->n; |
---|
| 451 | int j, k; |
---|
| 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; |
---|
| 460 | } |
---|
| 461 | } |
---|
| 462 | /* remove terms corresponding to fixed variables */ |
---|
| 463 | ios_clean_vec(mir->agg_vec, DBL_EPSILON); |
---|
| 464 | #if _MIR_DEBUG |
---|
| 465 | ios_check_vec(mir->agg_vec); |
---|
| 466 | #endif |
---|
| 467 | return; |
---|
| 468 | } |
---|
| 469 | |
---|
| 470 | static void bound_subst_heur(struct MIR *mir) |
---|
| 471 | { /* bound substitution heuristic */ |
---|
| 472 | int m = mir->m; |
---|
| 473 | int n = mir->n; |
---|
| 474 | int j, k, kk; |
---|
| 475 | double d1, d2; |
---|
| 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 */ |
---|
| 481 | kk = mir->vlb[k]; |
---|
| 482 | if (kk == 0) |
---|
| 483 | { if (mir->lb[k] == -DBL_MAX) |
---|
| 484 | d1 = DBL_MAX; |
---|
| 485 | else |
---|
| 486 | d1 = mir->x[k] - mir->lb[k]; |
---|
| 487 | } |
---|
| 488 | else |
---|
| 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]; |
---|
| 493 | } |
---|
| 494 | /* compute distance from x[k] to its upper bound */ |
---|
| 495 | kk = mir->vub[k]; |
---|
| 496 | if (kk == 0) |
---|
| 497 | { if (mir->vub[k] == +DBL_MAX) |
---|
| 498 | d2 = DBL_MAX; |
---|
| 499 | else |
---|
| 500 | d2 = mir->ub[k] - mir->x[k]; |
---|
| 501 | } |
---|
| 502 | else |
---|
| 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]; |
---|
| 507 | } |
---|
| 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] == '?'); |
---|
| 512 | if (d1 <= d2) |
---|
| 513 | mir->subst[k] = 'L'; |
---|
| 514 | else |
---|
| 515 | mir->subst[k] = 'U'; |
---|
| 516 | } |
---|
| 517 | return; |
---|
| 518 | } |
---|
| 519 | |
---|
| 520 | static void build_mod_row(struct MIR *mir) |
---|
| 521 | { /* substitute bounds and build modified constraint */ |
---|
| 522 | int m = mir->m; |
---|
| 523 | int n = mir->n; |
---|
| 524 | int j, jj, k, kk; |
---|
| 525 | /* initially modified constraint is aggregated constraint */ |
---|
| 526 | ios_copy_vec(mir->mod_vec, mir->agg_vec); |
---|
| 527 | mir->mod_rhs = mir->agg_rhs; |
---|
| 528 | #if _MIR_DEBUG |
---|
| 529 | ios_check_vec(mir->mod_vec); |
---|
| 530 | #endif |
---|
| 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); |
---|
| 541 | kk = mir->vlb[k]; |
---|
| 542 | if (kk == 0) |
---|
| 543 | { /* x[k] = lb[k] + x'[k] */ |
---|
| 544 | mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k]; |
---|
| 545 | } |
---|
| 546 | else |
---|
| 547 | { /* x[k] = lb[k] * x[kk] + x'[k] */ |
---|
| 548 | xassert(mir->isint[kk]); |
---|
| 549 | jj = mir->mod_vec->pos[kk]; |
---|
| 550 | if (jj == 0) |
---|
| 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; |
---|
| 554 | } |
---|
| 555 | mir->mod_vec->val[jj] += |
---|
| 556 | mir->mod_vec->val[j] * mir->lb[k]; |
---|
| 557 | } |
---|
| 558 | } |
---|
| 559 | else if (mir->subst[k] == 'U') |
---|
| 560 | { /* x[k] = (upper bound) - x'[k] */ |
---|
| 561 | xassert(mir->ub[k] != +DBL_MAX); |
---|
| 562 | kk = mir->vub[k]; |
---|
| 563 | if (kk == 0) |
---|
| 564 | { /* x[k] = ub[k] - x'[k] */ |
---|
| 565 | mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k]; |
---|
| 566 | } |
---|
| 567 | else |
---|
| 568 | { /* x[k] = ub[k] * x[kk] - x'[k] */ |
---|
| 569 | xassert(mir->isint[kk]); |
---|
| 570 | jj = mir->mod_vec->pos[kk]; |
---|
| 571 | if (jj == 0) |
---|
| 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; |
---|
| 575 | } |
---|
| 576 | mir->mod_vec->val[jj] += |
---|
| 577 | mir->mod_vec->val[j] * mir->ub[k]; |
---|
| 578 | } |
---|
| 579 | mir->mod_vec->val[j] = - mir->mod_vec->val[j]; |
---|
| 580 | } |
---|
| 581 | else |
---|
| 582 | xassert(k != k); |
---|
| 583 | } |
---|
| 584 | #if _MIR_DEBUG |
---|
| 585 | ios_check_vec(mir->mod_vec); |
---|
| 586 | #endif |
---|
| 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] */ |
---|
| 597 | mir->subst[k] = 'L'; |
---|
| 598 | mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k]; |
---|
| 599 | } |
---|
| 600 | else |
---|
| 601 | { /* x[k] = ub[k] - x'[k] */ |
---|
| 602 | mir->subst[k] = 'U'; |
---|
| 603 | mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k]; |
---|
| 604 | mir->mod_vec->val[j] = - mir->mod_vec->val[j]; |
---|
| 605 | } |
---|
| 606 | } |
---|
| 607 | #if _MIR_DEBUG |
---|
| 608 | ios_check_vec(mir->mod_vec); |
---|
| 609 | #endif |
---|
| 610 | return; |
---|
| 611 | } |
---|
| 612 | |
---|
| 613 | #if _MIR_DEBUG |
---|
| 614 | static void check_mod_row(struct MIR *mir) |
---|
| 615 | { /* check modified constraint */ |
---|
| 616 | int m = mir->m; |
---|
| 617 | int n = mir->n; |
---|
| 618 | int j, k, kk; |
---|
| 619 | double r, big, x; |
---|
| 620 | /* compute the residual r = sum a'[k] * x'[k] - b' and determine |
---|
| 621 | big = max(1, |a[k]|, |b|) */ |
---|
| 622 | r = 0.0, big = 1.0; |
---|
| 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); |
---|
| 629 | kk = mir->vlb[k]; |
---|
| 630 | if (kk == 0) |
---|
| 631 | x = mir->x[k] - mir->lb[k]; |
---|
| 632 | else |
---|
| 633 | x = mir->x[k] - mir->lb[k] * mir->x[kk]; |
---|
| 634 | } |
---|
| 635 | else if (mir->subst[k] == 'U') |
---|
| 636 | { /* x'[k] = (upper bound) - x[k] */ |
---|
| 637 | xassert(mir->ub[k] != +DBL_MAX); |
---|
| 638 | kk = mir->vub[k]; |
---|
| 639 | if (kk == 0) |
---|
| 640 | x = mir->ub[k] - mir->x[k]; |
---|
| 641 | else |
---|
| 642 | x = mir->ub[k] * mir->x[kk] - mir->x[k]; |
---|
| 643 | } |
---|
| 644 | else |
---|
| 645 | xassert(k != 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]); |
---|
| 649 | } |
---|
| 650 | r -= mir->mod_rhs; |
---|
| 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); |
---|
| 655 | return; |
---|
| 656 | } |
---|
| 657 | #endif |
---|
| 658 | |
---|
| 659 | /*********************************************************************** |
---|
| 660 | * mir_ineq - construct MIR inequality |
---|
| 661 | * |
---|
| 662 | * Given the single constraint mixed integer set |
---|
| 663 | * |
---|
| 664 | * |N| |
---|
| 665 | * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s}, |
---|
| 666 | * + + j in N |
---|
| 667 | * |
---|
| 668 | * this routine constructs the mixed integer rounding (MIR) inequality |
---|
| 669 | * |
---|
| 670 | * sum alpha[j] * x[j] <= beta + gamma * s, |
---|
| 671 | * j in N |
---|
| 672 | * |
---|
| 673 | * which is valid for X. |
---|
| 674 | * |
---|
| 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. */ |
---|
| 679 | |
---|
| 680 | static int mir_ineq(const int n, const double a[], const double b, |
---|
| 681 | double alpha[], double *beta, double *gamma) |
---|
| 682 | { int j; |
---|
| 683 | double f, t; |
---|
| 684 | if (fabs(b - floor(b + .5)) < 0.01) |
---|
| 685 | return 1; |
---|
| 686 | f = b - floor(b); |
---|
| 687 | for (j = 1; j <= n; j++) |
---|
| 688 | { t = (a[j] - floor(a[j])) - f; |
---|
| 689 | if (t <= 0.0) |
---|
| 690 | alpha[j] = floor(a[j]); |
---|
| 691 | else |
---|
| 692 | alpha[j] = floor(a[j]) + t / (1.0 - f); |
---|
| 693 | } |
---|
| 694 | *beta = floor(b); |
---|
| 695 | *gamma = 1.0 / (1.0 - f); |
---|
| 696 | return 0; |
---|
| 697 | } |
---|
| 698 | |
---|
| 699 | /*********************************************************************** |
---|
| 700 | * cmir_ineq - construct c-MIR inequality |
---|
| 701 | * |
---|
| 702 | * Given the mixed knapsack set |
---|
| 703 | * |
---|
| 704 | * MK |N| |
---|
| 705 | * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s, |
---|
| 706 | * + + j in N |
---|
| 707 | * |
---|
| 708 | * x[j] <= u[j]}, |
---|
| 709 | * |
---|
| 710 | * a subset C of variables to be complemented, and a divisor delta > 0, |
---|
| 711 | * this routine constructs the complemented MIR (c-MIR) inequality |
---|
| 712 | * |
---|
| 713 | * sum alpha[j] * x[j] <= beta + gamma * s, |
---|
| 714 | * j in N |
---|
| 715 | * MK |
---|
| 716 | * which is valid for X . |
---|
| 717 | * |
---|
| 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. */ |
---|
| 722 | |
---|
| 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) |
---|
| 726 | { int j; |
---|
| 727 | double *aa, bb; |
---|
| 728 | aa = alpha, bb = b; |
---|
| 729 | for (j = 1; j <= n; j++) |
---|
| 730 | { aa[j] = a[j] / delta; |
---|
| 731 | if (cset[j]) |
---|
| 732 | aa[j] = - aa[j], bb -= a[j] * u[j]; |
---|
| 733 | } |
---|
| 734 | bb /= delta; |
---|
| 735 | if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1; |
---|
| 736 | for (j = 1; j <= n; j++) |
---|
| 737 | { if (cset[j]) |
---|
| 738 | alpha[j] = - alpha[j], *beta += alpha[j] * u[j]; |
---|
| 739 | } |
---|
| 740 | *gamma /= delta; |
---|
| 741 | return 0; |
---|
| 742 | } |
---|
| 743 | |
---|
| 744 | /*********************************************************************** |
---|
| 745 | * cmir_sep - c-MIR separation heuristic |
---|
| 746 | * |
---|
| 747 | * Given the mixed knapsack set |
---|
| 748 | * |
---|
| 749 | * MK |N| |
---|
| 750 | * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s, |
---|
| 751 | * + + j in N |
---|
| 752 | * |
---|
| 753 | * x[j] <= u[j]} |
---|
| 754 | * |
---|
| 755 | * * * |
---|
| 756 | * and a fractional point (x , s ), this routine tries to construct |
---|
| 757 | * c-MIR inequality |
---|
| 758 | * |
---|
| 759 | * sum alpha[j] * x[j] <= beta + gamma * s, |
---|
| 760 | * j in N |
---|
| 761 | * MK |
---|
| 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. |
---|
| 766 | * |
---|
| 767 | * If a violated c-MIR inequality has been successfully constructed, |
---|
| 768 | * the routine returns its violation: |
---|
| 769 | * |
---|
| 770 | * * * |
---|
| 771 | * sum alpha[j] * x [j] - beta - gamma * s , |
---|
| 772 | * j in N |
---|
| 773 | * |
---|
| 774 | * which is positive. In case of failure the routine returns zero. */ |
---|
| 775 | |
---|
| 776 | struct vset { int j; double v; }; |
---|
| 777 | |
---|
| 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; |
---|
| 782 | return 0; |
---|
| 783 | } |
---|
| 784 | |
---|
| 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; |
---|
| 790 | char *cset; |
---|
| 791 | struct vset *vset; |
---|
| 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, |
---|
| 807 | gamma); |
---|
| 808 | if (fail) continue; |
---|
| 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]); |
---|
| 813 | } |
---|
| 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, |
---|
| 818 | respectively */ |
---|
| 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, |
---|
| 825 | gamma); |
---|
| 826 | if (fail) continue; |
---|
| 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]; |
---|
| 831 | } |
---|
| 832 | /* build subset of variables lying strictly between their bounds |
---|
| 833 | and order it by nondecreasing values of |x[j] - u[j]/2| */ |
---|
| 834 | nv = 0; |
---|
| 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 */ |
---|
| 840 | nv++; |
---|
| 841 | vset[nv].j = j; |
---|
| 842 | vset[nv].v = fabs(x[j] - 0.5 * u[j]); |
---|
| 843 | } |
---|
| 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++) |
---|
| 848 | { j = vset[v].j; |
---|
| 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 */ |
---|
| 856 | if (fail) continue; |
---|
| 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]; |
---|
| 861 | } |
---|
| 862 | /* construct the best c-MIR inequality chosen */ |
---|
| 863 | fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma); |
---|
| 864 | xassert(!fail); |
---|
| 865 | done: /* free working arrays */ |
---|
| 866 | xfree(cset); |
---|
| 867 | xfree(vset); |
---|
| 868 | /* return to the calling routine */ |
---|
| 869 | return r_best; |
---|
| 870 | } |
---|
| 871 | |
---|
| 872 | static double generate(struct MIR *mir) |
---|
| 873 | { /* try to generate violated c-MIR cut for modified constraint */ |
---|
| 874 | int m = mir->m; |
---|
| 875 | int n = mir->n; |
---|
| 876 | int j, k, kk, nint; |
---|
| 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 |
---|
| 881 | variable bounds */ |
---|
| 882 | ios_clean_vec(mir->cut_vec, DBL_EPSILON); |
---|
| 883 | #if _MIR_DEBUG |
---|
| 884 | ios_check_vec(mir->cut_vec); |
---|
| 885 | #endif |
---|
| 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; |
---|
| 892 | } |
---|
| 893 | ios_clean_vec(mir->cut_vec, 0.0); |
---|
| 894 | #if _MIR_DEBUG |
---|
| 895 | ios_check_vec(mir->cut_vec); |
---|
| 896 | #endif |
---|
| 897 | /* move integer terms to the beginning of the sparse vector and |
---|
| 898 | determine the number of integer variables */ |
---|
| 899 | nint = 0; |
---|
| 900 | for (j = 1; j <= mir->cut_vec->nnz; j++) |
---|
| 901 | { k = mir->cut_vec->ind[j]; |
---|
| 902 | xassert(1 <= k && k <= m+n); |
---|
| 903 | if (mir->isint[k]) |
---|
| 904 | { double temp; |
---|
| 905 | nint++; |
---|
| 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; |
---|
| 915 | } |
---|
| 916 | } |
---|
| 917 | #if _MIR_DEBUG |
---|
| 918 | ios_check_vec(mir->cut_vec); |
---|
| 919 | #endif |
---|
| 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]; |
---|
| 937 | else |
---|
| 938 | xassert(k != k); |
---|
| 939 | xassert(x[j] >= -0.001); |
---|
| 940 | if (x[j] < 0.0) x[j] = 0.0; |
---|
| 941 | } |
---|
| 942 | /* compute s = - sum of continuous terms */ |
---|
| 943 | s = 0.0; |
---|
| 944 | for (j = nint+1; j <= mir->cut_vec->nnz; j++) |
---|
| 945 | { double x; |
---|
| 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); |
---|
| 952 | kk = mir->vlb[k]; |
---|
| 953 | if (kk == 0) |
---|
| 954 | x = mir->x[k] - mir->lb[k]; |
---|
| 955 | else |
---|
| 956 | x = mir->x[k] - mir->lb[k] * mir->x[kk]; |
---|
| 957 | } |
---|
| 958 | else if (mir->subst[k] == 'U') |
---|
| 959 | { xassert(mir->ub[k] != +DBL_MAX); |
---|
| 960 | kk = mir->vub[k]; |
---|
| 961 | if (kk == 0) |
---|
| 962 | x = mir->ub[k] - mir->x[k]; |
---|
| 963 | else |
---|
| 964 | x = mir->ub[k] * mir->x[kk] - mir->x[k]; |
---|
| 965 | } |
---|
| 966 | else |
---|
| 967 | xassert(k != k); |
---|
| 968 | xassert(x >= -0.001); |
---|
| 969 | if (x < 0.0) x = 0.0; |
---|
| 970 | s -= mir->cut_vec->val[j] * x; |
---|
| 971 | } |
---|
| 972 | xassert(s >= 0.0); |
---|
| 973 | /* apply heuristic to obtain most violated c-MIR inequality */ |
---|
| 974 | b = mir->cut_rhs; |
---|
| 975 | r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha, |
---|
| 976 | &beta, &gamma); |
---|
| 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; |
---|
| 986 | } |
---|
| 987 | mir->cut_rhs = beta; |
---|
| 988 | #if _MIR_DEBUG |
---|
| 989 | ios_check_vec(mir->cut_vec); |
---|
| 990 | #endif |
---|
| 991 | skip: /* free working arrays */ |
---|
| 992 | xfree(u); |
---|
| 993 | xfree(x); |
---|
| 994 | xfree(alpha); |
---|
| 995 | done: return r_best; |
---|
| 996 | } |
---|
| 997 | |
---|
| 998 | #if _MIR_DEBUG |
---|
| 999 | static void check_raw_cut(struct MIR *mir, double r_best) |
---|
| 1000 | { /* check raw cut before back bound substitution */ |
---|
| 1001 | int m = mir->m; |
---|
| 1002 | int n = mir->n; |
---|
| 1003 | int j, k, kk; |
---|
| 1004 | double r, big, x; |
---|
| 1005 | /* compute the residual r = sum a[k] * x[k] - b and determine |
---|
| 1006 | big = max(1, |a[k]|, |b|) */ |
---|
| 1007 | r = 0.0, big = 1.0; |
---|
| 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); |
---|
| 1013 | kk = mir->vlb[k]; |
---|
| 1014 | if (kk == 0) |
---|
| 1015 | x = mir->x[k] - mir->lb[k]; |
---|
| 1016 | else |
---|
| 1017 | x = mir->x[k] - mir->lb[k] * mir->x[kk]; |
---|
| 1018 | } |
---|
| 1019 | else if (mir->subst[k] == 'U') |
---|
| 1020 | { xassert(mir->ub[k] != +DBL_MAX); |
---|
| 1021 | kk = mir->vub[k]; |
---|
| 1022 | if (kk == 0) |
---|
| 1023 | x = mir->ub[k] - mir->x[k]; |
---|
| 1024 | else |
---|
| 1025 | x = mir->ub[k] * mir->x[kk] - mir->x[k]; |
---|
| 1026 | } |
---|
| 1027 | else |
---|
| 1028 | xassert(k != 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]); |
---|
| 1032 | } |
---|
| 1033 | r -= mir->cut_rhs; |
---|
| 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); |
---|
| 1038 | return; |
---|
| 1039 | } |
---|
| 1040 | #endif |
---|
| 1041 | |
---|
| 1042 | static void back_subst(struct MIR *mir) |
---|
| 1043 | { /* back substitution of original bounds */ |
---|
| 1044 | int m = mir->m; |
---|
| 1045 | int n = mir->n; |
---|
| 1046 | int j, jj, k, kk; |
---|
| 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]; |
---|
| 1059 | } |
---|
| 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]; |
---|
| 1066 | } |
---|
| 1067 | else |
---|
| 1068 | xassert(k != k); |
---|
| 1069 | } |
---|
| 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); |
---|
| 1078 | kk = mir->vlb[k]; |
---|
| 1079 | if (kk == 0) |
---|
| 1080 | { /* x'[k] = x[k] - lb[k] */ |
---|
| 1081 | mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k]; |
---|
| 1082 | } |
---|
| 1083 | else |
---|
| 1084 | { /* x'[k] = x[k] - lb[k] * x[kk] */ |
---|
| 1085 | jj = mir->cut_vec->pos[kk]; |
---|
| 1086 | #if 0 |
---|
| 1087 | xassert(jj != 0); |
---|
| 1088 | #else |
---|
| 1089 | if (jj == 0) |
---|
| 1090 | { ios_set_vj(mir->cut_vec, kk, 1.0); |
---|
| 1091 | jj = mir->cut_vec->pos[kk]; |
---|
| 1092 | xassert(jj != 0); |
---|
| 1093 | mir->cut_vec->val[jj] = 0.0; |
---|
| 1094 | } |
---|
| 1095 | #endif |
---|
| 1096 | mir->cut_vec->val[jj] -= mir->cut_vec->val[j] * |
---|
| 1097 | mir->lb[k]; |
---|
| 1098 | } |
---|
| 1099 | } |
---|
| 1100 | else if (mir->subst[k] == 'U') |
---|
| 1101 | { /* x'[k] = (upper bound) - x[k] */ |
---|
| 1102 | xassert(mir->ub[k] != +DBL_MAX); |
---|
| 1103 | kk = mir->vub[k]; |
---|
| 1104 | if (kk == 0) |
---|
| 1105 | { /* x'[k] = ub[k] - x[k] */ |
---|
| 1106 | mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k]; |
---|
| 1107 | } |
---|
| 1108 | else |
---|
| 1109 | { /* x'[k] = ub[k] * x[kk] - x[k] */ |
---|
| 1110 | jj = mir->cut_vec->pos[kk]; |
---|
| 1111 | if (jj == 0) |
---|
| 1112 | { ios_set_vj(mir->cut_vec, kk, 1.0); |
---|
| 1113 | jj = mir->cut_vec->pos[kk]; |
---|
| 1114 | xassert(jj != 0); |
---|
| 1115 | mir->cut_vec->val[jj] = 0.0; |
---|
| 1116 | } |
---|
| 1117 | mir->cut_vec->val[jj] += mir->cut_vec->val[j] * |
---|
| 1118 | mir->ub[k]; |
---|
| 1119 | } |
---|
| 1120 | mir->cut_vec->val[j] = - mir->cut_vec->val[j]; |
---|
| 1121 | } |
---|
| 1122 | else |
---|
| 1123 | xassert(k != k); |
---|
| 1124 | } |
---|
| 1125 | #if _MIR_DEBUG |
---|
| 1126 | ios_check_vec(mir->cut_vec); |
---|
| 1127 | #endif |
---|
| 1128 | return; |
---|
| 1129 | } |
---|
| 1130 | |
---|
| 1131 | #if _MIR_DEBUG |
---|
| 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 */ |
---|
| 1135 | int m = mir->m; |
---|
| 1136 | int n = mir->n; |
---|
| 1137 | int j, k; |
---|
| 1138 | double r, big; |
---|
| 1139 | /* compute the residual r = sum a[k] * x[k] - b and determine |
---|
| 1140 | big = max(1, |a[k]|, |b|) */ |
---|
| 1141 | r = 0.0, big = 1.0; |
---|
| 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]); |
---|
| 1148 | } |
---|
| 1149 | r -= mir->cut_rhs; |
---|
| 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); |
---|
| 1154 | return; |
---|
| 1155 | } |
---|
| 1156 | #endif |
---|
| 1157 | |
---|
| 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; |
---|
| 1161 | int m = mir->m; |
---|
| 1162 | int n = mir->n; |
---|
| 1163 | GLPAIJ *aij; |
---|
| 1164 | int j, k, kk, jj; |
---|
| 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]; |
---|
| 1172 | if (jj == 0) |
---|
| 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; |
---|
| 1176 | } |
---|
| 1177 | mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val; |
---|
| 1178 | } |
---|
| 1179 | mir->cut_vec->val[j] = 0.0; |
---|
| 1180 | } |
---|
| 1181 | ios_clean_vec(mir->cut_vec, 0.0); |
---|
| 1182 | return; |
---|
| 1183 | } |
---|
| 1184 | |
---|
| 1185 | static void add_cut(glp_tree *tree, struct MIR *mir) |
---|
| 1186 | { /* add constructed cut inequality to the cut pool */ |
---|
| 1187 | int m = mir->m; |
---|
| 1188 | int n = mir->n; |
---|
| 1189 | int j, k, len; |
---|
| 1190 | int *ind = xcalloc(1+n, sizeof(int)); |
---|
| 1191 | double *val = xcalloc(1+n, sizeof(double)); |
---|
| 1192 | len = 0; |
---|
| 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]; |
---|
| 1197 | } |
---|
| 1198 | #if 0 |
---|
| 1199 | ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP, |
---|
| 1200 | mir->cut_rhs); |
---|
| 1201 | #else |
---|
| 1202 | glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP, |
---|
| 1203 | mir->cut_rhs); |
---|
| 1204 | #endif |
---|
| 1205 | xfree(ind); |
---|
| 1206 | xfree(val); |
---|
| 1207 | return; |
---|
| 1208 | } |
---|
| 1209 | |
---|
| 1210 | static int aggregate_row(glp_tree *tree, struct MIR *mir) |
---|
| 1211 | { /* try to aggregate another row */ |
---|
| 1212 | glp_prob *mip = tree->mip; |
---|
| 1213 | int m = mir->m; |
---|
| 1214 | int n = mir->n; |
---|
| 1215 | GLPAIJ *aij; |
---|
| 1216 | IOSVEC *v; |
---|
| 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 */ |
---|
| 1228 | kk = mir->vlb[k]; |
---|
| 1229 | if (kk == 0) |
---|
| 1230 | { if (mir->lb[k] == -DBL_MAX) |
---|
| 1231 | d1 = DBL_MAX; |
---|
| 1232 | else |
---|
| 1233 | d1 = mir->x[k] - mir->lb[k]; |
---|
| 1234 | } |
---|
| 1235 | else |
---|
| 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]; |
---|
| 1240 | } |
---|
| 1241 | /* compute distance from x[k] to its upper bound */ |
---|
| 1242 | kk = mir->vub[k]; |
---|
| 1243 | if (kk == 0) |
---|
| 1244 | { if (mir->vub[k] == +DBL_MAX) |
---|
| 1245 | d2 = DBL_MAX; |
---|
| 1246 | else |
---|
| 1247 | d2 = mir->ub[k] - mir->x[k]; |
---|
| 1248 | } |
---|
| 1249 | else |
---|
| 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]; |
---|
| 1254 | } |
---|
| 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; |
---|
| 1263 | } |
---|
| 1264 | if (kappa == 0) |
---|
| 1265 | { /* nothing chosen */ |
---|
| 1266 | ret = 1; |
---|
| 1267 | goto done; |
---|
| 1268 | } |
---|
| 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; |
---|
| 1279 | } |
---|
| 1280 | if (ii > m) |
---|
| 1281 | { /* nothing found */ |
---|
| 1282 | ret = 2; |
---|
| 1283 | goto done; |
---|
| 1284 | } |
---|
| 1285 | /* row ii has been found; include it in the aggregated list */ |
---|
| 1286 | mir->agg_cnt++; |
---|
| 1287 | xassert(mir->agg_cnt <= MAXAGGR); |
---|
| 1288 | mir->agg_row[mir->agg_cnt] = ii; |
---|
| 1289 | mir->skip[ii] = 2; |
---|
| 1290 | /* v := new row */ |
---|
| 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); |
---|
| 1295 | #if _MIR_DEBUG |
---|
| 1296 | ios_check_vec(v); |
---|
| 1297 | #endif |
---|
| 1298 | /* perform gaussian elimination to remove x[kappa] */ |
---|
| 1299 | j = mir->agg_vec->pos[kappa]; |
---|
| 1300 | xassert(j != 0); |
---|
| 1301 | jj = v->pos[kappa]; |
---|
| 1302 | xassert(jj != 0); |
---|
| 1303 | ios_linear_comb(mir->agg_vec, |
---|
| 1304 | - mir->agg_vec->val[j] / v->val[jj], v); |
---|
| 1305 | ios_delete_vec(v); |
---|
| 1306 | ios_set_vj(mir->agg_vec, kappa, 0.0); |
---|
| 1307 | #if _MIR_DEBUG |
---|
| 1308 | ios_check_vec(mir->agg_vec); |
---|
| 1309 | #endif |
---|
| 1310 | done: return ret; |
---|
| 1311 | } |
---|
| 1312 | |
---|
| 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; |
---|
| 1317 | int m = mir->m; |
---|
| 1318 | int n = mir->n; |
---|
| 1319 | int i; |
---|
| 1320 | double r_best; |
---|
| 1321 | xassert(mip->m >= m); |
---|
| 1322 | xassert(mip->n == n); |
---|
| 1323 | /* obtain current point */ |
---|
| 1324 | get_current_point(tree, mir); |
---|
| 1325 | #if _MIR_DEBUG |
---|
| 1326 | /* check current point */ |
---|
| 1327 | check_current_point(mir); |
---|
| 1328 | #endif |
---|
| 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); |
---|
| 1336 | loop: ; |
---|
| 1337 | #if _MIR_DEBUG |
---|
| 1338 | /* check aggregated row */ |
---|
| 1339 | check_agg_row(mir); |
---|
| 1340 | #endif |
---|
| 1341 | /* substitute fixed variables into aggregated constraint */ |
---|
| 1342 | subst_fixed_vars(mir); |
---|
| 1343 | #if _MIR_DEBUG |
---|
| 1344 | /* check aggregated row */ |
---|
| 1345 | check_agg_row(mir); |
---|
| 1346 | #endif |
---|
| 1347 | #if _MIR_DEBUG |
---|
| 1348 | /* check bound substitution flags */ |
---|
| 1349 | { int k; |
---|
| 1350 | for (k = 1; k <= m+n; k++) |
---|
| 1351 | xassert(mir->subst[k] == '?'); |
---|
| 1352 | } |
---|
| 1353 | #endif |
---|
| 1354 | /* apply bound substitution heuristic */ |
---|
| 1355 | bound_subst_heur(mir); |
---|
| 1356 | /* substitute bounds and build modified constraint */ |
---|
| 1357 | build_mod_row(mir); |
---|
| 1358 | #if _MIR_DEBUG |
---|
| 1359 | /* check modified row */ |
---|
| 1360 | check_mod_row(mir); |
---|
| 1361 | #endif |
---|
| 1362 | /* try to generate violated c-MIR cut for modified row */ |
---|
| 1363 | r_best = generate(mir); |
---|
| 1364 | if (r_best > 0.0) |
---|
| 1365 | { /* success */ |
---|
| 1366 | #if _MIR_DEBUG |
---|
| 1367 | /* check raw cut before back bound substitution */ |
---|
| 1368 | check_raw_cut(mir, r_best); |
---|
| 1369 | #endif |
---|
| 1370 | /* back substitution of original bounds */ |
---|
| 1371 | back_subst(mir); |
---|
| 1372 | #if _MIR_DEBUG |
---|
| 1373 | /* check the cut after back bound substitution */ |
---|
| 1374 | check_cut_row(mir, r_best); |
---|
| 1375 | #endif |
---|
| 1376 | /* final substitution to eliminate auxiliary variables */ |
---|
| 1377 | subst_aux_vars(tree, mir); |
---|
| 1378 | #if _MIR_DEBUG |
---|
| 1379 | /* check the cut after elimination of auxiliaries */ |
---|
| 1380 | check_cut_row(mir, r_best); |
---|
| 1381 | #endif |
---|
| 1382 | /* add constructed cut inequality to the cut pool */ |
---|
| 1383 | add_cut(tree, mir); |
---|
| 1384 | } |
---|
| 1385 | /* reset bound substitution flags */ |
---|
| 1386 | { int j, k; |
---|
| 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] = '?'; |
---|
| 1392 | } |
---|
| 1393 | } |
---|
| 1394 | if (r_best == 0.0) |
---|
| 1395 | { /* failure */ |
---|
| 1396 | if (mir->agg_cnt < MAXAGGR) |
---|
| 1397 | { /* try to aggregate another row */ |
---|
| 1398 | if (aggregate_row(tree, mir) == 0) goto loop; |
---|
| 1399 | } |
---|
| 1400 | } |
---|
| 1401 | /* unmark rows used in the aggregated constraint */ |
---|
| 1402 | { int k, ii; |
---|
| 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); |
---|
| 1407 | mir->skip[ii] = 0; |
---|
| 1408 | } |
---|
| 1409 | } |
---|
| 1410 | } |
---|
| 1411 | return; |
---|
| 1412 | } |
---|
| 1413 | |
---|
| 1414 | /*********************************************************************** |
---|
| 1415 | * NAME |
---|
| 1416 | * |
---|
| 1417 | * ios_mir_term - terminate MIR cut generator |
---|
| 1418 | * |
---|
| 1419 | * SYNOPSIS |
---|
| 1420 | * |
---|
| 1421 | * #include "glpios.h" |
---|
| 1422 | * void ios_mir_term(void *gen); |
---|
| 1423 | * |
---|
| 1424 | * DESCRIPTION |
---|
| 1425 | * |
---|
| 1426 | * The routine ios_mir_term deletes the MIR cut generator working area |
---|
| 1427 | * freeing all the memory allocated to it. */ |
---|
| 1428 | |
---|
| 1429 | void ios_mir_term(void *gen) |
---|
| 1430 | { struct MIR *mir = gen; |
---|
| 1431 | xfree(mir->skip); |
---|
| 1432 | xfree(mir->isint); |
---|
| 1433 | xfree(mir->lb); |
---|
| 1434 | xfree(mir->vlb); |
---|
| 1435 | xfree(mir->ub); |
---|
| 1436 | xfree(mir->vub); |
---|
| 1437 | xfree(mir->x); |
---|
| 1438 | xfree(mir->agg_row); |
---|
| 1439 | ios_delete_vec(mir->agg_vec); |
---|
| 1440 | xfree(mir->subst); |
---|
| 1441 | ios_delete_vec(mir->mod_vec); |
---|
| 1442 | ios_delete_vec(mir->cut_vec); |
---|
| 1443 | xfree(mir); |
---|
| 1444 | return; |
---|
| 1445 | } |
---|
| 1446 | |
---|
| 1447 | /* eof */ |
---|