| 1 | /* $Id: CoinPresolveDoubleton.cpp 1448 2011-06-19 15:34:41Z stefan $ */ |
| 2 | // Copyright (C) 2002, International Business Machines |
| 3 | // Corporation and others. All Rights Reserved. |
| 4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
| 5 | |
| 6 | #include <stdio.h> |
| 7 | #include <math.h> |
| 8 | |
| 9 | #include "CoinFinite.hpp" |
| 10 | #include "CoinHelperFunctions.hpp" |
| 11 | #include "CoinPresolveMatrix.hpp" |
| 12 | |
| 13 | #include "CoinPresolveEmpty.hpp" // for DROP_COL/DROP_ROW |
| 14 | #include "CoinPresolveZeros.hpp" |
| 15 | #include "CoinPresolveFixed.hpp" |
| 16 | #include "CoinPresolveDoubleton.hpp" |
| 17 | |
| 18 | #include "CoinPresolvePsdebug.hpp" |
| 19 | #include "CoinMessage.hpp" |
| 20 | |
| 21 | #if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
| 22 | #include "CoinPresolvePsdebug.hpp" |
| 23 | #endif |
| 24 | |
| 25 | |
| 26 | namespace { /* begin unnamed local namespace */ |
| 27 | |
| 28 | /* |
| 29 | This routine does the grunt work needed to substitute x for y in all rows i |
| 30 | where coeff[i,y] != 0. We have |
| 31 | |
| 32 | y = (c - a*x)/b = c/b + (-a/b)*x |
| 33 | |
| 34 | Suppose we're fixing row i. We need to adjust the row bounds by |
| 35 | -coeff[i,y]*(c/b) and coeff[i,x] by coeff[i,y]*(-a/b). The value |
| 36 | c/b is passed as the bounds_factor, and -a/b as the coeff_factor. |
| 37 | |
| 38 | row0 is the doubleton row. It is assumed that coeff[row0,y] has been |
| 39 | removed from the column major representation before this routine is |
| 40 | called. (Otherwise, we'd have to check for it to avoid a useless row |
| 41 | update.) |
| 42 | |
| 43 | Both the row and col representations are updated. There are two cases: |
| 44 | |
| 45 | * coeff[i,x] != 0: |
| 46 | in the column rep, modify coeff[i,x]; |
| 47 | in the row rep, modify coeff[i,x] and drop coeff[i,y]. |
| 48 | |
| 49 | * coeff[i,x] == 0 (i.e., non-existent): |
| 50 | in the column rep, add coeff[i,x]; mcstrt is modified if the column |
| 51 | must be moved; |
| 52 | in the row rep, convert coeff[i,y] to coeff[i,x]. |
| 53 | |
| 54 | The row and column reps are inconsistent during the routine and at |
| 55 | completion. In the row rep, column x and y are updated except for |
| 56 | the doubleton row, and in the column rep only column x is updated |
| 57 | except for coeff[row0,x]. On return, column y and row row0 will be deleted |
| 58 | and consistency will be restored. |
| 59 | */ |
| 60 | |
| 61 | bool elim_doubleton (const char * |
| 62 | #ifdef PRESOLVE_DEBUG |
| 63 | msg |
| 64 | #endif |
| 65 | , |
| 66 | CoinBigIndex *mcstrt, |
| 67 | double *rlo, double *rup, |
| 68 | double *colels, |
| 69 | int *hrow, int *hcol, |
| 70 | int *hinrow, int *hincol, |
| 71 | presolvehlink *clink, int ncols, |
| 72 | CoinBigIndex *mrstrt, double *rowels, |
| 73 | double coeff_factor, |
| 74 | double bounds_factor, |
| 75 | int |
| 76 | #ifdef PRESOLVE_DEBUG |
| 77 | row0 |
| 78 | #endif |
| 79 | , int icolx, int icoly) |
| 80 | |
| 81 | { |
| 82 | CoinBigIndex kcsx = mcstrt[icolx]; |
| 83 | CoinBigIndex kcex = kcsx + hincol[icolx]; |
| 84 | |
| 85 | # if PRESOLVE_DEBUG |
| 86 | printf("%s %d x=%d y=%d cf=%g bf=%g nx=%d yrows=(" , msg, |
| 87 | row0, icolx, icoly, coeff_factor, bounds_factor, hincol[icolx]); |
| 88 | # endif |
| 89 | /* |
| 90 | Open a loop to scan column y. For each nonzero coefficient (row,y), |
| 91 | update column x and the row bounds for the row. |
| 92 | |
| 93 | The initial assert checks that we're properly updating column x. |
| 94 | */ |
| 95 | CoinBigIndex base = mcstrt[icoly]; |
| 96 | int numberInY = hincol[icoly]; |
| 97 | for (int kwhere = 0 ; kwhere < numberInY ; kwhere++) |
| 98 | { PRESOLVEASSERT(kcex == kcsx+hincol[icolx]) ; |
| 99 | CoinBigIndex kcoly = base+kwhere; |
| 100 | /* |
| 101 | Look for coeff[row,x], then update accordingly. |
| 102 | */ |
| 103 | double coeffy = colels[kcoly] ; |
| 104 | double delta = coeffy*coeff_factor ; |
| 105 | int row = hrow[kcoly] ; |
| 106 | CoinBigIndex kcolx = presolve_find_row1(row,kcsx,kcex,hrow) ; |
| 107 | # if PRESOLVE_DEBUG |
| 108 | printf("%d%s " ,row,(kcolx<kcex)?"+" :"" ) ; |
| 109 | # endif |
| 110 | /* |
| 111 | Case 1: coeff[i,x] != 0: update it in column and row reps; drop coeff[i,y] |
| 112 | from row rep. |
| 113 | */ |
| 114 | if (kcolx < kcex) |
| 115 | { colels[kcolx] += delta ; |
| 116 | |
| 117 | CoinBigIndex kmi = presolve_find_col(icolx,mrstrt[row], |
| 118 | mrstrt[row]+hinrow[row],hcol) ; |
| 119 | rowels[kmi] = colels[kcolx] ; |
| 120 | presolve_delete_from_row(row,icoly,mrstrt,hinrow,hcol,rowels) ; } |
| 121 | /* |
| 122 | Case 2: coeff[i,x] == 0: add it in the column rep; convert coeff[i,y] in |
| 123 | the row rep. presolve_expand_col ensures an empty entry exists at the |
| 124 | end of the column. The location of column x may change with expansion. |
| 125 | */ |
| 126 | else |
| 127 | { bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol, |
| 128 | clink,ncols,icolx) ; |
| 129 | if (no_mem) |
| 130 | return (true) ; |
| 131 | |
| 132 | kcsx = mcstrt[icolx] ; |
| 133 | kcex = mcstrt[icolx]+hincol[icolx] ; |
| 134 | // recompute y as well |
| 135 | base = mcstrt[icoly]; |
| 136 | |
| 137 | hrow[kcex] = row ; |
| 138 | colels[kcex] = delta ; |
| 139 | hincol[icolx]++ ; |
| 140 | kcex++ ; |
| 141 | |
| 142 | CoinBigIndex k2 = presolve_find_col(icoly,mrstrt[row], |
| 143 | mrstrt[row]+hinrow[row],hcol) ; |
| 144 | hcol[k2] = icolx ; |
| 145 | rowels[k2] = delta ; } |
| 146 | /* |
| 147 | Update the row bounds, if necessary. Avoid updating finite infinity. |
| 148 | */ |
| 149 | if (bounds_factor != 0.0) |
| 150 | { delta = coeffy*bounds_factor ; |
| 151 | if (-PRESOLVE_INF < rlo[row]) |
| 152 | rlo[row] -= delta ; |
| 153 | if (rup[row] < PRESOLVE_INF) |
| 154 | rup[row] -= delta ; } } |
| 155 | |
| 156 | # if PRESOLVE_DEBUG |
| 157 | printf(")\n" ) ; |
| 158 | # endif |
| 159 | |
| 160 | return (false) ; } |
| 161 | |
| 162 | } /* end unnamed local namespace */ |
| 163 | |
| 164 | |
| 165 | /* |
| 166 | * It is always the case that one of the variables of a doubleton |
| 167 | * will be (implied) free, but neither will necessarily be a singleton. |
| 168 | * Since in the case of a doubleton the number of non-zero entries |
| 169 | * will never increase, though, it makes sense to always eliminate them. |
| 170 | * |
| 171 | * The col rep and row rep must be consistent. |
| 172 | */ |
| 173 | const CoinPresolveAction |
| 174 | *doubleton_action::presolve (CoinPresolveMatrix *prob, |
| 175 | const CoinPresolveAction *next) |
| 176 | |
| 177 | { |
| 178 | double startTime = 0.0; |
| 179 | int startEmptyRows=0; |
| 180 | int startEmptyColumns = 0; |
| 181 | if (prob->tuning_) { |
| 182 | startTime = CoinCpuTime(); |
| 183 | startEmptyRows = prob->countEmptyRows(); |
| 184 | startEmptyColumns = prob->countEmptyCols(); |
| 185 | } |
| 186 | double *colels = prob->colels_; |
| 187 | int *hrow = prob->hrow_; |
| 188 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 189 | int *hincol = prob->hincol_; |
| 190 | int ncols = prob->ncols_; |
| 191 | |
| 192 | double *clo = prob->clo_; |
| 193 | double *cup = prob->cup_; |
| 194 | |
| 195 | double *rowels = prob->rowels_; |
| 196 | int *hcol = prob->hcol_; |
| 197 | CoinBigIndex *mrstrt = prob->mrstrt_; |
| 198 | int *hinrow = prob->hinrow_; |
| 199 | int nrows = prob->nrows_; |
| 200 | |
| 201 | double *rlo = prob->rlo_; |
| 202 | double *rup = prob->rup_; |
| 203 | |
| 204 | presolvehlink *clink = prob->clink_; |
| 205 | presolvehlink *rlink = prob->rlink_; |
| 206 | |
| 207 | const unsigned char *integerType = prob->integerType_; |
| 208 | |
| 209 | double *cost = prob->cost_; |
| 210 | |
| 211 | int numberLook = prob->numberRowsToDo_; |
| 212 | int iLook; |
| 213 | int * look = prob->rowsToDo_; |
| 214 | const double ztolzb = prob->ztolzb_; |
| 215 | |
| 216 | action * actions = new action [nrows]; |
| 217 | int nactions = 0; |
| 218 | |
| 219 | int *zeros = prob->usefulColumnInt_; //new int[ncols]; |
| 220 | int nzeros = 0; |
| 221 | |
| 222 | int *fixed = zeros+ncols; //new int[ncols]; |
| 223 | int nfixed = 0; |
| 224 | |
| 225 | unsigned char *rowstat = prob->rowstat_; |
| 226 | double *acts = prob->acts_; |
| 227 | double * sol = prob->sol_; |
| 228 | |
| 229 | bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; |
| 230 | # if PRESOLVE_CONSISTENCY |
| 231 | presolve_consistent(prob) ; |
| 232 | presolve_links_ok(prob) ; |
| 233 | # endif |
| 234 | |
| 235 | // wasfor (int irow=0; irow<nrows; irow++) |
| 236 | for (iLook=0;iLook<numberLook;iLook++) { |
| 237 | int irow = look[iLook]; |
| 238 | if (hinrow[irow] == 2 && |
| 239 | fabs(rup[irow] - rlo[irow]) <= ZTOLDP) { |
| 240 | double rhs = rlo[irow]; |
| 241 | CoinBigIndex krs = mrstrt[irow]; |
| 242 | int icolx, icoly; |
| 243 | CoinBigIndex k; |
| 244 | |
| 245 | icolx = hcol[krs]; |
| 246 | icoly = hcol[krs+1]; |
| 247 | if (hincol[icolx]<=0||hincol[icoly]<=0) { |
| 248 | // should never happen ? |
| 249 | //printf("JJF - doubleton column %d has %d entries and %d has %d\n", |
| 250 | // icolx,hincol[icolx],icoly,hincol[icoly]); |
| 251 | continue; |
| 252 | } |
| 253 | // check size |
| 254 | if (fabs(rowels[krs]) < ZTOLDP2 || fabs(rowels[krs+1]) < ZTOLDP2) |
| 255 | continue; |
| 256 | // See if prohibited for any reason |
| 257 | if (prob->colProhibited(icolx) || prob->colProhibited(icolx)) |
| 258 | continue; |
| 259 | |
| 260 | // don't bother with fixed variables |
| 261 | if (!(fabs(cup[icolx] - clo[icolx]) < ZTOLDP) && |
| 262 | !(fabs(cup[icoly] - clo[icoly]) < ZTOLDP)) { |
| 263 | double coeffx, coeffy; |
| 264 | /* find this row in each of the columns */ |
| 265 | CoinBigIndex krowx = presolve_find_row(irow, mcstrt[icolx], mcstrt[icolx] + hincol[icolx], hrow); |
| 266 | CoinBigIndex krowy = presolve_find_row(irow, mcstrt[icoly], mcstrt[icoly] + hincol[icoly], hrow); |
| 267 | |
| 268 | /* |
| 269 | Check for integrality: If one variable is integer, keep it and substitute |
| 270 | for the continuous variable. If both are integer, substitute only for the |
| 271 | forms x = k * y (k integral and non-empty intersection on bounds on x) |
| 272 | or x = 1-y, where both x and y are binary. |
| 273 | |
| 274 | flag bits for integerStatus: 1>>0 x integer |
| 275 | 1>>1 y integer |
| 276 | */ |
| 277 | int integerStatus=0; |
| 278 | if (integerType[icolx]) { |
| 279 | if (integerType[icoly]) { |
| 280 | // both integer |
| 281 | int good = 0; |
| 282 | double rhs2 = rhs; |
| 283 | double value; |
| 284 | value=colels[krowx]; |
| 285 | if (value<0.0) { |
| 286 | value = - value; |
| 287 | rhs2 += 1; |
| 288 | } |
| 289 | if (cup[icolx]==1.0&&clo[icolx]==0.0&&fabs(value-1.0)<1.0e-7) |
| 290 | good =1; |
| 291 | value=colels[krowy]; |
| 292 | if (value<0.0) { |
| 293 | value = - value; |
| 294 | rhs2 += 1; |
| 295 | } |
| 296 | if (cup[icoly]==1.0&&clo[icoly]==0.0&&fabs(value-1.0)<1.0e-7) |
| 297 | good |= 2; |
| 298 | if (good==3&&fabs(rhs2-1.0)<1.0e-7) |
| 299 | integerStatus = 3; |
| 300 | else |
| 301 | integerStatus=-1; |
| 302 | if (integerStatus==-1&&!rhs) { |
| 303 | // maybe x = k * y; |
| 304 | double value1 = colels[krowx]; |
| 305 | double value2 = colels[krowy]; |
| 306 | double ratio; |
| 307 | bool swap=false; |
| 308 | if (fabs(value1)>fabs(value2)) { |
| 309 | ratio = value1/value2; |
| 310 | } else { |
| 311 | ratio = value2/value1; |
| 312 | swap=true; |
| 313 | } |
| 314 | ratio=fabs(ratio); |
| 315 | if (fabs(ratio-floor(ratio+0.5))<1.0e-12) { |
| 316 | // possible |
| 317 | integerStatus = swap ? 2 : 1; |
| 318 | //printf("poss type %d\n",integerStatus); |
| 319 | } |
| 320 | } |
| 321 | } else { |
| 322 | integerStatus = 1; |
| 323 | } |
| 324 | } else if (integerType[icoly]) { |
| 325 | integerStatus = 2; |
| 326 | } |
| 327 | if (integerStatus<0) { |
| 328 | // can still take in some cases |
| 329 | bool canDo=false; |
| 330 | double value1 = colels[krowx]; |
| 331 | double value2 = colels[krowy]; |
| 332 | double ratio; |
| 333 | bool swap=false; |
| 334 | double rhsRatio; |
| 335 | if (fabs(value1)>fabs(value2)) { |
| 336 | ratio = value1/value2; |
| 337 | rhsRatio = rhs/value1; |
| 338 | } else { |
| 339 | ratio = value2/value1; |
| 340 | rhsRatio = rhs/value2; |
| 341 | swap=true; |
| 342 | } |
| 343 | ratio=fabs(ratio); |
| 344 | if (fabs(ratio-floor(ratio+0.5))<1.0e-12) { |
| 345 | // possible |
| 346 | integerStatus = swap ? 2 : 1; |
| 347 | // but check rhs |
| 348 | if (rhsRatio==floor(rhsRatio+0.5)) |
| 349 | canDo=true; |
| 350 | } |
| 351 | #ifdef COIN_DEVELOP2 |
| 352 | if (canDo) |
| 353 | printf("Good CoinPresolveDoubleton icolx %d (%g and bounds %g %g) icoly %d (%g and bound %g %g) - rhs %g\n" , |
| 354 | icolx,colels[krowx],clo[icolx],cup[icolx], |
| 355 | icoly,colels[krowy],clo[icoly],cup[icoly],rhs); |
| 356 | else |
| 357 | printf("Bad CoinPresolveDoubleton icolx %d (%g) icoly %d (%g) - rhs %g\n" , |
| 358 | icolx,colels[krowx],icoly,colels[krowy],rhs); |
| 359 | #endif |
| 360 | if (!canDo) |
| 361 | continue; |
| 362 | } |
| 363 | if (integerStatus == 2) { |
| 364 | CoinSwap(icoly,icolx); |
| 365 | CoinSwap(krowy,krowx); |
| 366 | } |
| 367 | |
| 368 | // HAVE TO JIB WITH ABOVE swapS |
| 369 | // if x's coefficient is something like 1000, but y's only something like -1, |
| 370 | // then when we postsolve, if x's is close to being out of tolerance, |
| 371 | // then y is very likely to be (because y==1000x) . (55) |
| 372 | // It it interesting that the number of doubletons found may depend |
| 373 | // on which column is substituted away (this is true of baxter.mps). |
| 374 | if (!integerStatus) { |
| 375 | if (fabs(colels[krowy]) < fabs(colels[krowx])) { |
| 376 | CoinSwap(icoly,icolx); |
| 377 | CoinSwap(krowy,krowx); |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | #if 0 |
| 382 | //????? |
| 383 | if (integerType[icolx] && |
| 384 | clo[icoly] != -PRESOLVE_INF && |
| 385 | cup[icoly] != PRESOLVE_INF) { |
| 386 | continue; |
| 387 | } |
| 388 | #endif |
| 389 | |
| 390 | { |
| 391 | CoinBigIndex kcs = mcstrt[icoly]; |
| 392 | CoinBigIndex kce = kcs + hincol[icoly]; |
| 393 | for (k=kcs; k<kce; k++) { |
| 394 | if (hinrow[hrow[k]] == 1) { |
| 395 | break; |
| 396 | } |
| 397 | } |
| 398 | // let singleton rows be taken care of first |
| 399 | if (k<kce) |
| 400 | continue; |
| 401 | } |
| 402 | |
| 403 | coeffx = colels[krowx]; |
| 404 | coeffy = colels[krowy]; |
| 405 | |
| 406 | // it is possible that both x and y are singleton columns |
| 407 | // that can cause problems |
| 408 | if (hincol[icolx] == 1 && hincol[icoly] == 1) |
| 409 | continue; |
| 410 | |
| 411 | // BE CAUTIOUS and avoid very large relative differences |
| 412 | // if this is not done in baxter, then the computed solution isn't optimal, |
| 413 | // but gets it in 11995 iterations; the postsolve goes to iteration 16181. |
| 414 | // with this, the solution is optimal, but takes 18825 iters; postsolve 18871. |
| 415 | #if 0 |
| 416 | if (fabs(coeffx) * max_coeff_factor <= fabs(coeffy)) |
| 417 | continue; |
| 418 | #endif |
| 419 | |
| 420 | #if 0 |
| 421 | if (only_zero_rhs && rhs != 0) |
| 422 | continue; |
| 423 | |
| 424 | if (reject_doubleton(mcstrt, colels, hrow, hincol, |
| 425 | -coeffx / coeffy, |
| 426 | max_coeff_ratio, |
| 427 | irow, icolx, icoly)) |
| 428 | continue; |
| 429 | #endif |
| 430 | |
| 431 | // common equations are of the form ax + by = 0, or x + y >= lo |
| 432 | { |
| 433 | PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n" , |
| 434 | icoly,icolx,irow)); |
| 435 | action *s = &actions[nactions]; |
| 436 | nactions++; |
| 437 | |
| 438 | s->row = irow; |
| 439 | s->icolx = icolx; |
| 440 | |
| 441 | s->clox = clo[icolx]; |
| 442 | s->cupx = cup[icolx]; |
| 443 | s->costx = cost[icolx]; |
| 444 | |
| 445 | s->icoly = icoly; |
| 446 | s->costy = cost[icoly]; |
| 447 | |
| 448 | s->rlo = rlo[irow]; |
| 449 | |
| 450 | s->coeffx = coeffx; |
| 451 | |
| 452 | s->coeffy = coeffy; |
| 453 | |
| 454 | s->ncolx = hincol[icolx]; |
| 455 | |
| 456 | s->ncoly = hincol[icoly]; |
| 457 | if (s->ncoly<s->ncolx) { |
| 458 | // Take out row |
| 459 | s->colel = presolve_dupmajor(colels,hrow,hincol[icoly], |
| 460 | mcstrt[icoly],irow) ; |
| 461 | s->ncolx=0; |
| 462 | } else { |
| 463 | s->colel = presolve_dupmajor(colels,hrow,hincol[icolx], |
| 464 | mcstrt[icolx],irow) ; |
| 465 | s->ncoly=0; |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | /* |
| 470 | * This moves the bounds information for y onto x, |
| 471 | * making y free and allowing us to substitute it away. |
| 472 | * |
| 473 | * a x + b y = c |
| 474 | * l1 <= x <= u1 |
| 475 | * l2 <= y <= u2 ==> |
| 476 | * |
| 477 | * l2 <= (c - a x) / b <= u2 |
| 478 | * b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a |
| 479 | * b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a |
| 480 | */ |
| 481 | { |
| 482 | double lo1 = -PRESOLVE_INF; |
| 483 | double up1 = PRESOLVE_INF; |
| 484 | |
| 485 | //PRESOLVEASSERT((coeffx < 0) == (coeffy/-coeffx < 0)); |
| 486 | // (coeffy/-coeffx < 0) == (coeffy<0 == coeffx<0) |
| 487 | if (-PRESOLVE_INF < clo[icoly]) { |
| 488 | if (coeffx * coeffy < 0) |
| 489 | lo1 = (coeffy * clo[icoly] - rhs) / -coeffx; |
| 490 | else |
| 491 | up1 = (coeffy * clo[icoly] - rhs) / -coeffx; |
| 492 | } |
| 493 | |
| 494 | if (cup[icoly] < PRESOLVE_INF) { |
| 495 | if (coeffx * coeffy < 0) |
| 496 | up1 = (coeffy * cup[icoly] - rhs) / -coeffx; |
| 497 | else |
| 498 | lo1 = (coeffy * cup[icoly] - rhs) / -coeffx; |
| 499 | } |
| 500 | |
| 501 | // costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b |
| 502 | // the effect of maxmin cancels out |
| 503 | cost[icolx] += cost[icoly] * (-coeffx / coeffy); |
| 504 | |
| 505 | prob->change_bias(cost[icoly] * rhs / coeffy); |
| 506 | |
| 507 | if (0 /*integerType[icolx]*/) { |
| 508 | abort(); |
| 509 | /* no change possible for now */ |
| 510 | #if 0 |
| 511 | lo1 = trunc(lo1); |
| 512 | up1 = trunc(up1); |
| 513 | |
| 514 | /* trunc(3.5) == 3.0 */ |
| 515 | /* trunc(-3.5) == -3.0 */ |
| 516 | |
| 517 | /* I think this is ok */ |
| 518 | if (lo1 > clo[icolx]) { |
| 519 | (clo[icolx] <= 0.0) |
| 520 | clo[icolx] = ? ilo |
| 521 | |
| 522 | clo[icolx] = ilo; |
| 523 | cup[icolx] = iup; |
| 524 | } |
| 525 | #endif |
| 526 | } else { |
| 527 | double lo2 = CoinMax(clo[icolx], lo1); |
| 528 | double up2 = CoinMin(cup[icolx], up1); |
| 529 | if (lo2 > up2) { |
| 530 | if (lo2 <= up2 + prob->feasibilityTolerance_||fixInfeasibility) { |
| 531 | // If close to integer then go there |
| 532 | double nearest = floor(lo2+0.5); |
| 533 | if (fabs(nearest-lo2)<2.0*prob->feasibilityTolerance_) { |
| 534 | lo2 = nearest; |
| 535 | up2 = nearest; |
| 536 | } else { |
| 537 | lo2 = up2; |
| 538 | } |
| 539 | } else { |
| 540 | prob->status_ |= 1; |
| 541 | prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, |
| 542 | prob->messages()) |
| 543 | <<icolx |
| 544 | <<lo2 |
| 545 | <<up2 |
| 546 | <<CoinMessageEol; |
| 547 | break; |
| 548 | } |
| 549 | } |
| 550 | clo[icolx] = lo2; |
| 551 | cup[icolx] = up2; |
| 552 | |
| 553 | if (rowstat&&sol) { |
| 554 | // update solution and basis |
| 555 | int basisChoice=0; |
| 556 | int numberBasic=0; |
| 557 | double movement = 0 ; |
| 558 | if (prob->columnIsBasic(icolx)) |
| 559 | numberBasic++; |
| 560 | if (prob->columnIsBasic(icoly)) |
| 561 | numberBasic++; |
| 562 | if (prob->rowIsBasic(irow)) |
| 563 | numberBasic++; |
| 564 | if (sol[icolx]<=lo2+ztolzb) { |
| 565 | movement = lo2-sol[icolx] ; |
| 566 | sol[icolx] = lo2; |
| 567 | prob->setColumnStatus(icolx,CoinPrePostsolveMatrix::atLowerBound); |
| 568 | } else if (sol[icolx]>=up2-ztolzb) { |
| 569 | movement = up2-sol[icolx] ; |
| 570 | sol[icolx] = up2; |
| 571 | prob->setColumnStatus(icolx,CoinPrePostsolveMatrix::atUpperBound); |
| 572 | } else { |
| 573 | basisChoice=1; |
| 574 | } |
| 575 | if (numberBasic>1) |
| 576 | prob->setColumnStatus(icolx,CoinPrePostsolveMatrix::basic); |
| 577 | /* |
| 578 | We need to compensate if x was forced to move. Beyond that, even if x didn't |
| 579 | move, we've forced y = (c-ax)/b, and that might not have been true before. So |
| 580 | even if x didn't move, y may have moved. Note that the constant term c/b is |
| 581 | subtracted out as the constraints are modified, so we don't include it when |
| 582 | calculating movement for y. |
| 583 | */ |
| 584 | if (movement) |
| 585 | { CoinBigIndex k; |
| 586 | for (k = mcstrt[icolx] ; k < mcstrt[icolx]+hincol[icolx] ; k++) |
| 587 | { int row = hrow[k]; |
| 588 | if (hinrow[row]) |
| 589 | acts[row] += movement*colels[k]; } } |
| 590 | movement = (-coeffx*sol[icolx]/coeffy)-sol[icoly] ; |
| 591 | if (movement) |
| 592 | { for (k = mcstrt[icoly] ; |
| 593 | k < mcstrt[icoly]+hincol[icoly] ; |
| 594 | k++) |
| 595 | { int row = hrow[k]; |
| 596 | if (hinrow[row]) |
| 597 | acts[row] += movement*colels[k]; } } |
| 598 | } |
| 599 | if (lo2 == up2) |
| 600 | fixed[nfixed++] = icolx; |
| 601 | } |
| 602 | } |
| 603 | |
| 604 | // Update next set of actions |
| 605 | { |
| 606 | prob->addCol(icolx); |
| 607 | int i,kcs,kce; |
| 608 | kcs = mcstrt[icoly]; |
| 609 | kce = kcs + hincol[icoly]; |
| 610 | for (i=kcs;i<kce;i++) { |
| 611 | int row = hrow[i]; |
| 612 | prob->addRow(row); |
| 613 | } |
| 614 | kcs = mcstrt[icolx]; |
| 615 | kce = kcs + hincol[icolx]; |
| 616 | for (i=kcs;i<kce;i++) { |
| 617 | int row = hrow[i]; |
| 618 | prob->addRow(row); |
| 619 | } |
| 620 | } |
| 621 | |
| 622 | /* |
| 623 | Empty irow in the column-major matrix. Deleting the coefficient for |
| 624 | (irow,icoly) is a bit costly (given that we're about to drop the whole |
| 625 | column), but saves the trouble of checking for it in elim_doubleton. |
| 626 | */ |
| 627 | presolve_delete_from_col(irow,icolx,mcstrt,hincol,hrow,colels) ; |
| 628 | presolve_delete_from_col(irow,icoly,mcstrt,hincol,hrow,colels) ; |
| 629 | /* |
| 630 | Drop irow in the row-major representation: set the length to 0 |
| 631 | and reclaim the major vector space in bulk storage. |
| 632 | */ |
| 633 | hinrow[irow] = 0; |
| 634 | PRESOLVE_REMOVE_LINK(rlink,irow); |
| 635 | |
| 636 | /* transfer the colx factors to coly */ |
| 637 | bool no_mem = elim_doubleton("ELIMD" , |
| 638 | mcstrt, rlo, rup, colels, |
| 639 | hrow, hcol, hinrow, hincol, |
| 640 | clink, ncols, |
| 641 | mrstrt, rowels, |
| 642 | -coeffx / coeffy, |
| 643 | rhs / coeffy, |
| 644 | irow, icolx, icoly); |
| 645 | if (no_mem) |
| 646 | throwCoinError("out of memory" , |
| 647 | "doubleton_action::presolve" ); |
| 648 | |
| 649 | |
| 650 | // eliminate coly entirely from the col rep |
| 651 | hincol[icoly] = 0; |
| 652 | PRESOLVE_REMOVE_LINK(clink, icoly); |
| 653 | cost[icoly] = 0.0; |
| 654 | |
| 655 | rlo[irow] = 0.0; |
| 656 | rup[irow] = 0.0; |
| 657 | |
| 658 | zeros[nzeros++] = icolx; // check for zeros |
| 659 | |
| 660 | // strictly speaking, since we didn't adjust {clo,cup}[icoly] |
| 661 | // or {rlo,rup}[irow], this col/row may be infeasible, |
| 662 | // because the solution/activity would be 0, whereas the |
| 663 | // bounds may be non-zero. |
| 664 | } |
| 665 | |
| 666 | # if PRESOLVE_CONSISTENCY |
| 667 | presolve_consistent(prob) ; |
| 668 | presolve_links_ok(prob) ; |
| 669 | # endif |
| 670 | } |
| 671 | } |
| 672 | |
| 673 | if (nactions) { |
| 674 | # if PRESOLVE_SUMMARY |
| 675 | printf("NDOUBLETONS: %d\n" , nactions); |
| 676 | # endif |
| 677 | action *actions1 = new action[nactions]; |
| 678 | CoinMemcpyN(actions, nactions, actions1); |
| 679 | |
| 680 | next = new doubleton_action(nactions, actions1, next); |
| 681 | |
| 682 | if (nzeros) |
| 683 | next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next); |
| 684 | if (nfixed) |
| 685 | next = remove_fixed_action::presolve(prob, fixed, nfixed, next); |
| 686 | } |
| 687 | |
| 688 | //delete[]zeros; |
| 689 | //delete[]fixed; |
| 690 | deleteAction(actions,action*); |
| 691 | |
| 692 | if (prob->tuning_) { |
| 693 | double thisTime=CoinCpuTime(); |
| 694 | int droppedRows = prob->countEmptyRows() - startEmptyRows ; |
| 695 | int droppedColumns = prob->countEmptyCols() - startEmptyColumns; |
| 696 | printf("CoinPresolveDoubleton(4) - %d rows, %d columns dropped in time %g, total %g\n" , |
| 697 | droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); |
| 698 | } |
| 699 | return (next); |
| 700 | } |
| 701 | |
| 702 | /* |
| 703 | Reintroduce the column (y) and doubleton row (irow) removed in presolve. |
| 704 | Correct the other column (x) involved in the doubleton, update the solution, |
| 705 | etc. |
| 706 | |
| 707 | A fair amount of complication arises because the presolve transform saves the |
| 708 | shorter of x or y. Postsolve thus includes portions to restore either. |
| 709 | */ |
| 710 | void doubleton_action::postsolve(CoinPostsolveMatrix *prob) const |
| 711 | { |
| 712 | const action *const actions = actions_; |
| 713 | const int nactions = nactions_; |
| 714 | |
| 715 | double *colels = prob->colels_; |
| 716 | int *hrow = prob->hrow_; |
| 717 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 718 | int *hincol = prob->hincol_; |
| 719 | int *link = prob->link_; |
| 720 | |
| 721 | double *clo = prob->clo_; |
| 722 | double *cup = prob->cup_; |
| 723 | |
| 724 | double *rlo = prob->rlo_; |
| 725 | double *rup = prob->rup_; |
| 726 | |
| 727 | double *dcost = prob->cost_; |
| 728 | |
| 729 | double *sol = prob->sol_; |
| 730 | double *acts = prob->acts_; |
| 731 | double *rowduals = prob->rowduals_; |
| 732 | double *rcosts = prob->rcosts_; |
| 733 | |
| 734 | unsigned char *colstat = prob->colstat_; |
| 735 | unsigned char *rowstat = prob->rowstat_; |
| 736 | |
| 737 | const double maxmin = prob->maxmin_; |
| 738 | |
| 739 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
| 740 | char *cdone = prob->cdone_; |
| 741 | char *rdone = prob->rdone_; |
| 742 | # endif |
| 743 | |
| 744 | CoinBigIndex &free_list = prob->free_list_; |
| 745 | |
| 746 | const double ztolzb = prob->ztolzb_; |
| 747 | const double ztoldj = prob->ztoldj_; |
| 748 | |
| 749 | int nrows = prob->nrows_; |
| 750 | // Arrays to rebuild the unsaved column. |
| 751 | int * index1 = new int[nrows]; |
| 752 | double * element1 = new double[nrows]; |
| 753 | CoinZeroN(element1,nrows); |
| 754 | |
| 755 | # if PRESOLVE_CONSISTENCY |
| 756 | presolve_check_threads(prob) ; |
| 757 | # endif |
| 758 | # if PRESOLVE_DEBUG |
| 759 | presolve_check_sol(prob) ; |
| 760 | # endif |
| 761 | /* |
| 762 | The outer loop: step through the doubletons in this array of actions. |
| 763 | The first activity is to unpack the doubleton. |
| 764 | */ |
| 765 | for (const action *f = &actions[nactions-1]; actions<=f; f--) { |
| 766 | |
| 767 | int irow = f->row; |
| 768 | double lo0 = f->clox; |
| 769 | double up0 = f->cupx; |
| 770 | |
| 771 | |
| 772 | double coeffx = f->coeffx; |
| 773 | double coeffy = f->coeffy; |
| 774 | int jcolx = f->icolx; |
| 775 | int jcoly = f->icoly; |
| 776 | |
| 777 | double rhs = f->rlo; |
| 778 | /* |
| 779 | jcolx is in the problem (for whatever reason), and the doubleton row (irow) |
| 780 | and column (jcoly) have only been processed by empty row/column postsolve |
| 781 | (i.e., reintroduced with length 0). |
| 782 | */ |
| 783 | PRESOLVEASSERT(cdone[jcolx] && rdone[irow]==DROP_ROW); |
| 784 | PRESOLVEASSERT(cdone[jcoly]==DROP_COL); |
| 785 | |
| 786 | /* |
| 787 | Restore bounds for doubleton row, bounds and objective coefficient for x, |
| 788 | objective for y. |
| 789 | |
| 790 | Original comment: restoration of rlo and rup likely isn't necessary. |
| 791 | */ |
| 792 | rlo[irow] = f->rlo; |
| 793 | rup[irow] = f->rlo; |
| 794 | |
| 795 | clo[jcolx] = lo0; |
| 796 | cup[jcolx] = up0; |
| 797 | |
| 798 | dcost[jcolx] = f->costx; |
| 799 | dcost[jcoly] = f->costy; |
| 800 | |
| 801 | #if PRESOLVE_DEBUG |
| 802 | /* Original comment: I've forgotten what this is about |
| 803 | |
| 804 | Loss of significant digits through cancellation, with possible inflation |
| 805 | when divided by coeffy below? -- lh, 040831 -- |
| 806 | */ |
| 807 | if ((rhs < 0) == ((coeffx * sol[jcolx]) < 0) && |
| 808 | fabs(rhs - coeffx * sol[jcolx]) * 100 < rhs && |
| 809 | fabs(rhs - coeffx * sol[jcolx]) * 100 < (coeffx * sol[jcolx])) |
| 810 | printf("DANGEROUS RHS??? %g %g %g\n" , |
| 811 | rhs, coeffx * sol[jcolx], |
| 812 | (rhs - coeffx * sol[jcolx])); |
| 813 | #endif |
| 814 | /* |
| 815 | Set primal solution for y (including status) and row activity for the |
| 816 | doubleton row. The motivation (up in presolve) for wanting coeffx < coeffy |
| 817 | is to avoid inflation into sol[y]. Since this is a (satisfied) equality, |
| 818 | activity is the rhs value and the logical is nonbasic. |
| 819 | */ |
| 820 | sol[jcoly] = (rhs-coeffx*sol[jcolx])/coeffy; |
| 821 | acts[irow] = rhs; |
| 822 | if (rowstat) |
| 823 | prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound); |
| 824 | /* |
| 825 | Time to get into the correction/restoration of coefficients for columns x |
| 826 | and y, with attendant correction of row bounds and activities. Accumulate |
| 827 | partial reduced costs (missing the contribution from the doubleton row) so |
| 828 | that we can eventually calculate a dual for the doubleton row. |
| 829 | */ |
| 830 | double djy = maxmin * dcost[jcoly]; |
| 831 | double djx = maxmin * dcost[jcolx]; |
| 832 | double bounds_factor = rhs/coeffy; |
| 833 | /* |
| 834 | We saved column y in the action, so we'll use it to reconstruct column x. |
| 835 | There are two aspects: correction of existing x coefficients, and fill in. |
| 836 | Given |
| 837 | coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor |
| 838 | we have |
| 839 | coeffx[k] = coeffx'[k]-coeffy[k]*coeff_factor |
| 840 | where |
| 841 | coeff_factor = -coeffx[dblton]/coeffy[dblton]. |
| 842 | |
| 843 | Keep in mind that the major vector stored in the action does not include |
| 844 | the coefficient from the doubleton row --- the doubleton coefficients are |
| 845 | held in coeffx and coeffy. |
| 846 | */ |
| 847 | if (f->ncoly) { |
| 848 | int ncoly=f->ncoly-1; // as row taken out |
| 849 | double multiplier = coeffx/coeffy; |
| 850 | //printf("Current colx %d\n",jcolx); |
| 851 | int * indy = reinterpret_cast<int *>(f->colel+ncoly); |
| 852 | /* |
| 853 | Rebuild a threaded column y, starting with the end of the thread and working |
| 854 | back to the beginning. In the process, accumulate corrections to column x |
| 855 | in element1 and index1. Fix row bounds and activity as we go (add back the |
| 856 | constant correction removed in presolve), and accumulate contributions to |
| 857 | the reduced cost for y. |
| 858 | |
| 859 | The PRESOLVEASSERT says this row should already be present. |
| 860 | */ |
| 861 | int ystart = NO_LINK; |
| 862 | int nX=0; |
| 863 | int i,iRow; |
| 864 | for (i=0; i<ncoly; ++i) { |
| 865 | int iRow = indy[i]; |
| 866 | PRESOLVEASSERT(rdone[iRow]); |
| 867 | |
| 868 | double yValue = f->colel[i]; |
| 869 | |
| 870 | // undo elim_doubleton(1) |
| 871 | if (-PRESOLVE_INF < rlo[iRow]) |
| 872 | rlo[iRow] += yValue * bounds_factor; |
| 873 | |
| 874 | // undo elim_doubleton(2) |
| 875 | if (rup[iRow] < PRESOLVE_INF) |
| 876 | rup[iRow] += yValue * bounds_factor; |
| 877 | |
| 878 | acts[iRow] += yValue * bounds_factor; |
| 879 | |
| 880 | djy -= rowduals[iRow] * yValue; |
| 881 | /* |
| 882 | Link the coefficient into column y: Acquire the first free slot in the |
| 883 | bulk arrays and store the row index and coefficient. Then link the slot |
| 884 | in front of coefficients we've already processed. |
| 885 | */ |
| 886 | CoinBigIndex k = free_list; |
| 887 | assert(k >= 0 && k < prob->bulk0_) ; |
| 888 | free_list = link[free_list]; |
| 889 | hrow[k] = iRow; |
| 890 | colels[k] = yValue; |
| 891 | link[k] = ystart; |
| 892 | ystart = k; |
| 893 | /* |
| 894 | Calculate and store the correction to the x coefficient. |
| 895 | */ |
| 896 | yValue *= multiplier; |
| 897 | element1[iRow]=yValue; |
| 898 | index1[nX++]=iRow; |
| 899 | } |
| 900 | # if PRESOLVE_CONSISTENCY |
| 901 | presolve_check_free_list(prob) ; |
| 902 | # endif |
| 903 | /* |
| 904 | Handle the coefficients of the doubleton row. |
| 905 | */ |
| 906 | { |
| 907 | double yValue = coeffy; |
| 908 | |
| 909 | CoinBigIndex k = free_list; |
| 910 | assert(k >= 0 && k < prob->bulk0_) ; |
| 911 | free_list = link[free_list]; |
| 912 | hrow[k] = irow; |
| 913 | colels[k] = yValue; |
| 914 | link[k] = ystart; |
| 915 | ystart = k; |
| 916 | |
| 917 | yValue *= multiplier; |
| 918 | element1[irow]=yValue; |
| 919 | index1[nX++]=irow; |
| 920 | } |
| 921 | /* |
| 922 | Attach the threaded column y to mcstrt and record the length. |
| 923 | */ |
| 924 | mcstrt[jcoly] = ystart; |
| 925 | hincol[jcoly] = f->ncoly; |
| 926 | /* |
| 927 | Now integrate the corrections to column x. First thing to do is find the |
| 928 | end of the column. While we're doing that, correct any existing entries. |
| 929 | This complicates life because the correction could cancel the existing |
| 930 | coefficient and we don't want to leave an explicit zero. In this case we |
| 931 | relink the column around it. (last is a little misleading --- it's actually |
| 932 | `last nonzero'. If we haven't seen a nonzero yet, the relink goes to mcstrt.) |
| 933 | The freed slot is linked at the beginning of the free list. |
| 934 | */ |
| 935 | CoinBigIndex k=mcstrt[jcolx]; |
| 936 | CoinBigIndex last = NO_LINK; |
| 937 | int numberInColumn = hincol[jcolx]; |
| 938 | int numberToDo=numberInColumn; |
| 939 | for (i=0; i<numberToDo; ++i) { |
| 940 | iRow = hrow[k]; |
| 941 | assert (iRow>=0&&iRow<nrows); |
| 942 | double value = colels[k]+element1[iRow]; |
| 943 | element1[iRow]=0.0; |
| 944 | if (fabs(value)>=1.0e-15) { |
| 945 | colels[k]=value; |
| 946 | last=k; |
| 947 | k = link[k]; |
| 948 | if (iRow != irow) |
| 949 | djx -= rowduals[iRow] * value; |
| 950 | } else { |
| 951 | numberInColumn--; |
| 952 | // add to free list |
| 953 | int nextk = link[k]; |
| 954 | assert(free_list>=0); |
| 955 | link[k]=free_list; |
| 956 | free_list=k; |
| 957 | assert (k>=0); |
| 958 | k=nextk; |
| 959 | if (last!=NO_LINK) |
| 960 | link[last]=k; |
| 961 | else |
| 962 | mcstrt[jcolx]=k; |
| 963 | } |
| 964 | } |
| 965 | /* |
| 966 | We've found the end of column x. Any remaining nonzeros in element1 will be |
| 967 | fill in, which we link at the end of the column thread. |
| 968 | */ |
| 969 | for (i=0;i<nX;i++) { |
| 970 | int iRow = index1[i]; |
| 971 | double xValue = element1[iRow]; |
| 972 | element1[iRow]=0.0; |
| 973 | if (fabs(xValue)>=1.0e-15) { |
| 974 | if (iRow != irow) |
| 975 | djx -= rowduals[iRow] * xValue; |
| 976 | numberInColumn++; |
| 977 | CoinBigIndex k = free_list; |
| 978 | assert(k >= 0 && k < prob->bulk0_) ; |
| 979 | free_list = link[free_list]; |
| 980 | hrow[k] = iRow; |
| 981 | PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow); |
| 982 | colels[k] = xValue; |
| 983 | if (last!=NO_LINK) |
| 984 | link[last] = k; |
| 985 | else |
| 986 | mcstrt[jcolx]=k; |
| 987 | last = k; |
| 988 | } |
| 989 | } |
| 990 | |
| 991 | # if PRESOLVE_CONSISTENCY |
| 992 | presolve_check_free_list(prob) ; |
| 993 | # endif |
| 994 | |
| 995 | /* |
| 996 | Whew! Tidy up column x and we're done. |
| 997 | */ |
| 998 | link[last]=NO_LINK; |
| 999 | assert(numberInColumn); |
| 1000 | hincol[jcolx] = numberInColumn; |
| 1001 | /* |
| 1002 | Of course, we could have saved column x in the action. Now we need to |
| 1003 | regenerate coefficients of column y. |
| 1004 | Given |
| 1005 | coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor |
| 1006 | we have |
| 1007 | coeffy[k] = (coeffx'[k]-coeffx[k])*(1/coeff_factor) |
| 1008 | where |
| 1009 | coeff_factor = -coeffx[dblton]/coeffy[dblton]. |
| 1010 | */ |
| 1011 | } else { |
| 1012 | int ncolx=f->ncolx-1; |
| 1013 | double multiplier = -coeffy/coeffx; |
| 1014 | int * indx = reinterpret_cast<int *> (f->colel+ncolx); |
| 1015 | //printf("Current colx %d\n",jcolx); |
| 1016 | /* |
| 1017 | Scan existing column x to find the end. While we're at it, accumulate part |
| 1018 | of the new y coefficients in index1 and element1. |
| 1019 | */ |
| 1020 | CoinBigIndex k=mcstrt[jcolx]; |
| 1021 | int nX=0; |
| 1022 | int i,iRow; |
| 1023 | for (i=0; i<hincol[jcolx]-1; ++i) { |
| 1024 | if (colels[k]) { |
| 1025 | iRow = hrow[k]; |
| 1026 | index1[nX++]=iRow; |
| 1027 | element1[iRow]=multiplier*colels[k]; |
| 1028 | } |
| 1029 | k = link[k]; |
| 1030 | } |
| 1031 | if (colels[k]) { |
| 1032 | iRow = hrow[k]; |
| 1033 | index1[nX++]=iRow; |
| 1034 | element1[iRow]=multiplier*colels[k]; |
| 1035 | } |
| 1036 | /* |
| 1037 | Replace column x with the the original column x held in the doubleton |
| 1038 | action. We first move column x to the free list, then thread a column with |
| 1039 | the original coefficients, back to front. While we're at it, add the |
| 1040 | second part of the y coefficients to index1 and element1. |
| 1041 | */ |
| 1042 | multiplier = - multiplier; |
| 1043 | link[k] = free_list; |
| 1044 | free_list = mcstrt[jcolx]; |
| 1045 | int xstart = NO_LINK; |
| 1046 | for (i=0; i<ncolx; ++i) { |
| 1047 | int iRow = indx[i]; |
| 1048 | PRESOLVEASSERT(rdone[iRow]); |
| 1049 | |
| 1050 | double xValue = f->colel[i]; |
| 1051 | //printf("x %d %d %g\n",i,indx[i],f->colel[i]); |
| 1052 | CoinBigIndex k = free_list; |
| 1053 | assert(k >= 0 && k < prob->bulk0_) ; |
| 1054 | free_list = link[free_list]; |
| 1055 | hrow[k] = iRow; |
| 1056 | colels[k] = xValue; |
| 1057 | link[k] = xstart; |
| 1058 | xstart = k; |
| 1059 | |
| 1060 | djx -= rowduals[iRow] * xValue; |
| 1061 | |
| 1062 | xValue *= multiplier; |
| 1063 | if (!element1[iRow]) { |
| 1064 | element1[iRow]=xValue; |
| 1065 | index1[nX++]=iRow; |
| 1066 | } else { |
| 1067 | element1[iRow]+=xValue; |
| 1068 | } |
| 1069 | } |
| 1070 | # if PRESOLVE_CONSISTENCY |
| 1071 | presolve_check_free_list(prob) ; |
| 1072 | # endif |
| 1073 | /* |
| 1074 | The same, for the doubleton row. |
| 1075 | */ |
| 1076 | { |
| 1077 | double xValue = coeffx; |
| 1078 | CoinBigIndex k = free_list; |
| 1079 | assert(k >= 0 && k < prob->bulk0_) ; |
| 1080 | free_list = link[free_list]; |
| 1081 | hrow[k] = irow; |
| 1082 | colels[k] = xValue; |
| 1083 | link[k] = xstart; |
| 1084 | xstart = k; |
| 1085 | |
| 1086 | xValue *= multiplier; |
| 1087 | if (!element1[irow]) { |
| 1088 | element1[irow]=xValue; |
| 1089 | index1[nX++]=irow; |
| 1090 | } else { |
| 1091 | element1[irow]+=xValue; |
| 1092 | } |
| 1093 | } |
| 1094 | /* |
| 1095 | Link the new column x to mcstrt and set the length. |
| 1096 | */ |
| 1097 | mcstrt[jcolx] = xstart; |
| 1098 | hincol[jcolx] = f->ncolx; |
| 1099 | /* |
| 1100 | Now get to work building a threaded column y from the nonzeros in element1. |
| 1101 | As before, build the thread in reverse. |
| 1102 | */ |
| 1103 | int ystart = NO_LINK; |
| 1104 | int n=0; |
| 1105 | for (i=0;i<nX;i++) { |
| 1106 | int iRow = index1[i]; |
| 1107 | PRESOLVEASSERT(rdone[iRow] || iRow == irow); |
| 1108 | double yValue = element1[iRow]; |
| 1109 | element1[iRow]=0.0; |
| 1110 | if (fabs(yValue)>=1.0e-12) { |
| 1111 | n++; |
| 1112 | CoinBigIndex k = free_list; |
| 1113 | assert(k >= 0 && k < prob->bulk0_) ; |
| 1114 | free_list = link[free_list]; |
| 1115 | hrow[k] = iRow; |
| 1116 | colels[k] = yValue; |
| 1117 | link[k] = ystart; |
| 1118 | ystart = k; |
| 1119 | } |
| 1120 | } |
| 1121 | # if PRESOLVE_CONSISTENCY |
| 1122 | presolve_check_free_list(prob) ; |
| 1123 | # endif |
| 1124 | /* |
| 1125 | Tidy up --- link the new column into mcstrt and set the length. |
| 1126 | */ |
| 1127 | mcstrt[jcoly] = ystart; |
| 1128 | assert(n); |
| 1129 | hincol[jcoly] = n; |
| 1130 | /* |
| 1131 | Now that we have the original y, we can scan it and do the corrections to |
| 1132 | the row bounds and activity, and get a start on a reduced cost for y. |
| 1133 | */ |
| 1134 | k = mcstrt[jcoly]; |
| 1135 | int ny = hincol[jcoly]; |
| 1136 | for (i=0; i<ny; ++i) { |
| 1137 | int row = hrow[k]; |
| 1138 | double coeff = colels[k]; |
| 1139 | k = link[k]; |
| 1140 | |
| 1141 | if (row != irow) { |
| 1142 | |
| 1143 | // undo elim_doubleton(1) |
| 1144 | if (-PRESOLVE_INF < rlo[row]) |
| 1145 | rlo[row] += coeff * bounds_factor; |
| 1146 | |
| 1147 | // undo elim_doubleton(2) |
| 1148 | if (rup[row] < PRESOLVE_INF) |
| 1149 | rup[row] += coeff * bounds_factor; |
| 1150 | |
| 1151 | acts[row] += coeff * bounds_factor; |
| 1152 | |
| 1153 | djy -= rowduals[row] * coeff; |
| 1154 | } |
| 1155 | } |
| 1156 | /* |
| 1157 | Scan the new column x and calculate reduced costs. This could be integrated |
| 1158 | into the previous section where the original column x is restored. |
| 1159 | |
| 1160 | ok --- let's try it, then. |
| 1161 | |
| 1162 | k = mcstrt[jcolx]; |
| 1163 | int nx = hincol[jcolx]; |
| 1164 | |
| 1165 | for ( i=0; i<nx; ++i) { |
| 1166 | int row = hrow[k]; |
| 1167 | double coeff = colels[k]; |
| 1168 | k = link[k]; |
| 1169 | |
| 1170 | if (row != irow) { |
| 1171 | djx -= rowduals[row] * coeff; |
| 1172 | } |
| 1173 | } |
| 1174 | */ |
| 1175 | } |
| 1176 | /* |
| 1177 | Sanity? The only assignment to coeffx is f->coeffx! Ditto for coeffy. |
| 1178 | */ |
| 1179 | assert (fabs(coeffx-f->coeffx)<1.0e-6&&fabs(coeffy-f->coeffy)<1.0e-6); |
| 1180 | /* |
| 1181 | Time to calculate a dual for the doubleton row, and settle the status of x |
| 1182 | and y. Ideally, we'll leave x at whatever nonbasic status it currently has |
| 1183 | and make y basic. There's a potential problem, however: Remember that we |
| 1184 | transferred bounds from y to x when we eliminated y. If those bounds were |
| 1185 | tighter than x's original bounds, we may not be able to maintain x at its |
| 1186 | present status, or even as nonbasic. |
| 1187 | |
| 1188 | We'll make two claims here: |
| 1189 | |
| 1190 | * If the dual value for the doubleton row is chosen to keep the reduced |
| 1191 | cost djx of col x at its prior value, then the reduced cost djy of col |
| 1192 | y will be 0. (Crank through the linear algebra to convince yourself.) |
| 1193 | |
| 1194 | * If the bounds on x have loosened, then it must be possible to make y |
| 1195 | nonbasic, because we've transferred the tight bound back to y. (Yeah, |
| 1196 | I'm waving my hands. But it sounds good. -- lh, 040907 --) |
| 1197 | |
| 1198 | So ... if we can maintain x nonbasic, then we need to set y basic, which |
| 1199 | means we should calculate rowduals[dblton] so that rcost[jcoly] == 0. We |
| 1200 | may need to change the status of x (an artifact of loosening a bound when |
| 1201 | x was previously a fixed variable). |
| 1202 | |
| 1203 | If we need to push x into the basis, then we calculate rowduals[dblton] so |
| 1204 | that rcost[jcolx] == 0 and make y nonbasic. |
| 1205 | */ |
| 1206 | // printf("djs x - %g (%g), y - %g (%g)\n",djx,coeffx,djy,coeffy); |
| 1207 | if (colstat) |
| 1208 | { bool basicx = prob->columnIsBasic(jcolx) ; |
| 1209 | bool nblbxok = (fabs(lo0 - sol[jcolx]) < ztolzb) && |
| 1210 | (rcosts[jcolx] >= -ztoldj) ; |
| 1211 | bool nbubxok = (fabs(up0 - sol[jcolx]) < ztolzb) && |
| 1212 | (rcosts[jcolx] <= ztoldj) ; |
| 1213 | if (basicx || nblbxok || nbubxok) |
| 1214 | { if (!basicx) |
| 1215 | { if (nblbxok) |
| 1216 | { prob->setColumnStatus(jcolx, |
| 1217 | CoinPrePostsolveMatrix::atLowerBound) ; } |
| 1218 | else |
| 1219 | if (nbubxok) |
| 1220 | { prob->setColumnStatus(jcolx, |
| 1221 | CoinPrePostsolveMatrix::atUpperBound) ; } } |
| 1222 | prob->setColumnStatus(jcoly,CoinPrePostsolveMatrix::basic); |
| 1223 | rowduals[irow] = djy / coeffy; |
| 1224 | rcosts[jcolx] = djx - rowduals[irow] * coeffx; |
| 1225 | #if 0 |
| 1226 | if (prob->columnIsBasic(jcolx)) |
| 1227 | assert (fabs(rcosts[jcolx])<1.0e-5); |
| 1228 | #endif |
| 1229 | rcosts[jcoly] = 0.0; |
| 1230 | } else { |
| 1231 | prob->setColumnStatus(jcolx,CoinPrePostsolveMatrix::basic); |
| 1232 | prob->setColumnStatusUsingValue(jcoly); |
| 1233 | rowduals[irow] = djx / coeffx; |
| 1234 | rcosts[jcoly] = djy - rowduals[irow] * coeffy; |
| 1235 | rcosts[jcolx] = 0.0; |
| 1236 | } |
| 1237 | } else { |
| 1238 | // No status array |
| 1239 | // this is the coefficient we need to force col y's reduced cost to 0.0; |
| 1240 | // for example, this is obviously true if y is a singleton column |
| 1241 | rowduals[irow] = djy / coeffy; |
| 1242 | rcosts[jcoly] = 0.0; |
| 1243 | } |
| 1244 | |
| 1245 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
| 1246 | /* |
| 1247 | Mark the column and row as processed by doubleton action. The check integrity |
| 1248 | of the threaded matrix. |
| 1249 | */ |
| 1250 | cdone[jcoly] = DOUBLETON; |
| 1251 | rdone[irow] = DOUBLETON; |
| 1252 | presolve_check_threads(prob) ; |
| 1253 | #endif |
| 1254 | # if PRESOLVE_DEBUG |
| 1255 | /* |
| 1256 | Confirm accuracy of reduced cost for columns x and y. |
| 1257 | */ |
| 1258 | { |
| 1259 | CoinBigIndex k = mcstrt[jcolx]; |
| 1260 | int nx = hincol[jcolx]; |
| 1261 | double dj = maxmin * dcost[jcolx]; |
| 1262 | |
| 1263 | for (int i=0; i<nx; ++i) { |
| 1264 | int row = hrow[k]; |
| 1265 | double coeff = colels[k]; |
| 1266 | k = link[k]; |
| 1267 | |
| 1268 | dj -= rowduals[row] * coeff; |
| 1269 | } |
| 1270 | if (! (fabs(rcosts[jcolx] - dj) < 100*ZTOLDP)) |
| 1271 | printf("BAD DOUBLE X DJ: %d %d %g %g\n" , |
| 1272 | irow, jcolx, rcosts[jcolx], dj); |
| 1273 | rcosts[jcolx]=dj; |
| 1274 | } |
| 1275 | { |
| 1276 | CoinBigIndex k = mcstrt[jcoly]; |
| 1277 | int ny = hincol[jcoly]; |
| 1278 | double dj = maxmin * dcost[jcoly]; |
| 1279 | |
| 1280 | for (int i=0; i<ny; ++i) { |
| 1281 | int row = hrow[k]; |
| 1282 | double coeff = colels[k]; |
| 1283 | k = link[k]; |
| 1284 | |
| 1285 | dj -= rowduals[row] * coeff; |
| 1286 | //printf("b %d coeff %g dual %g dj %g\n", |
| 1287 | // row,coeff,rowduals[row],dj); |
| 1288 | } |
| 1289 | if (! (fabs(rcosts[jcoly] - dj) < 100*ZTOLDP)) |
| 1290 | printf("BAD DOUBLE Y DJ: %d %d %g %g\n" , |
| 1291 | irow, jcoly, rcosts[jcoly], dj); |
| 1292 | rcosts[jcoly]=dj; |
| 1293 | } |
| 1294 | # endif |
| 1295 | } |
| 1296 | /* |
| 1297 | Done at last. Delete the scratch arrays. |
| 1298 | */ |
| 1299 | |
| 1300 | delete [] index1; |
| 1301 | delete [] element1; |
| 1302 | } |
| 1303 | |
| 1304 | |
| 1305 | doubleton_action::~doubleton_action() |
| 1306 | { |
| 1307 | for (int i=nactions_-1; i>=0; i--) { |
| 1308 | delete[]actions_[i].colel; |
| 1309 | } |
| 1310 | deleteAction(actions_,action*); |
| 1311 | } |
| 1312 | |
| 1313 | |
| 1314 | |
| 1315 | static double *doubleton_mult; |
| 1316 | static int *doubleton_id; |
| 1317 | void check_doubletons(const CoinPresolveAction * paction) |
| 1318 | { |
| 1319 | const CoinPresolveAction * paction0 = paction; |
| 1320 | |
| 1321 | if (paction) { |
| 1322 | check_doubletons(paction->next); |
| 1323 | |
| 1324 | if (strcmp(paction0->name(), "doubleton_action" ) == 0) { |
| 1325 | const doubleton_action *daction = |
| 1326 | reinterpret_cast<const doubleton_action *>(paction0); |
| 1327 | for (int i=daction->nactions_-1; i>=0; --i) { |
| 1328 | int icolx = daction->actions_[i].icolx; |
| 1329 | int icoly = daction->actions_[i].icoly; |
| 1330 | double coeffx = daction->actions_[i].coeffx; |
| 1331 | double coeffy = daction->actions_[i].coeffy; |
| 1332 | |
| 1333 | doubleton_mult[icoly] = -coeffx/coeffy; |
| 1334 | doubleton_id[icoly] = icolx; |
| 1335 | } |
| 1336 | } |
| 1337 | } |
| 1338 | } |
| 1339 | |
| 1340 | #if PRESOLVE_DEBUG |
| 1341 | void check_doubletons1(const CoinPresolveAction * paction, |
| 1342 | int ncols) |
| 1343 | #else |
| 1344 | void check_doubletons1(const CoinPresolveAction * /*paction*/, |
| 1345 | int /*ncols*/) |
| 1346 | #endif |
| 1347 | { |
| 1348 | #if PRESOLVE_DEBUG |
| 1349 | doubleton_mult = new double[ncols]; |
| 1350 | doubleton_id = new int[ncols]; |
| 1351 | int i; |
| 1352 | for ( i=0; i<ncols; ++i) |
| 1353 | doubleton_id[i] = i; |
| 1354 | check_doubletons(paction); |
| 1355 | double minmult = 1.0; |
| 1356 | int minid = -1; |
| 1357 | for ( i=0; i<ncols; ++i) { |
| 1358 | double mult = 1.0; |
| 1359 | int j = i; |
| 1360 | if (doubleton_id[j] != j) { |
| 1361 | printf("MULTS (%d): " , j); |
| 1362 | while (doubleton_id[j] != j) { |
| 1363 | printf("%d %g, " , doubleton_id[j], doubleton_mult[j]); |
| 1364 | mult *= doubleton_mult[j]; |
| 1365 | j = doubleton_id[j]; |
| 1366 | } |
| 1367 | printf(" == %g\n" , mult); |
| 1368 | if (minmult > fabs(mult)) { |
| 1369 | minmult = fabs(mult); |
| 1370 | minid = i; |
| 1371 | } |
| 1372 | } |
| 1373 | } |
| 1374 | if (minid != -1) |
| 1375 | printf("MIN MULT: %d %g\n" , minid, minmult); |
| 1376 | #endif |
| 1377 | } |
| 1378 | |