| 1 | /* $Id: CoinPresolveFixed.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 "CoinPresolveMatrix.hpp" |
| 10 | #include "CoinPresolveFixed.hpp" |
| 11 | #include "CoinHelperFunctions.hpp" |
| 12 | #include "CoinFinite.hpp" |
| 13 | |
| 14 | #if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
| 15 | #include "CoinPresolvePsdebug.hpp" |
| 16 | #endif |
| 17 | |
| 18 | /* Begin routines associated with remove_fixed_action */ |
| 19 | |
| 20 | const char *remove_fixed_action::name() const |
| 21 | { |
| 22 | return ("remove_fixed_action" ); |
| 23 | } |
| 24 | |
| 25 | /* |
| 26 | * Original comment: |
| 27 | * |
| 28 | * invariant: both reps are loosely packed. |
| 29 | * coefficients of both reps remain consistent. |
| 30 | * |
| 31 | * Note that this concerns variables whose column bounds determine that |
| 32 | * they are slack; this does NOT concern singleton row constraints that |
| 33 | * determine that the relevant variable is slack. |
| 34 | * |
| 35 | * Invariant: col and row rep are consistent |
| 36 | */ |
| 37 | |
| 38 | /* |
| 39 | This routine empties the columns for the list of fixed variables passed in |
| 40 | (fcols, nfcols). As each coefficient a<ij> is set to 0, rlo<i> and rup<i> |
| 41 | are adjusted accordingly. Note, however, that c<j> is not considered to be |
| 42 | removed from the objective until column j is physically removed from the |
| 43 | matrix (drop_empty_cols_action), so the correction to the objective is |
| 44 | adjusted there. |
| 45 | |
| 46 | If a column solution is available, row activity (acts_) is adjusted. |
| 47 | remove_fixed_action implicitly assumes that the value of the variable has |
| 48 | already been forced within bounds. If this isn't true, the correction to |
| 49 | acts_ will be wrong. See make_fixed_action if you need to force the value |
| 50 | within bounds first. |
| 51 | */ |
| 52 | const remove_fixed_action* |
| 53 | remove_fixed_action::presolve (CoinPresolveMatrix *prob, |
| 54 | int *fcols, |
| 55 | int nfcols, |
| 56 | const CoinPresolveAction *next) |
| 57 | { |
| 58 | double *colels = prob->colels_; |
| 59 | int *hrow = prob->hrow_; |
| 60 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 61 | int *hincol = prob->hincol_; |
| 62 | |
| 63 | double *rowels = prob->rowels_; |
| 64 | int *hcol = prob->hcol_; |
| 65 | CoinBigIndex *mrstrt = prob->mrstrt_; |
| 66 | int *hinrow = prob->hinrow_; |
| 67 | |
| 68 | double *clo = prob->clo_; |
| 69 | double *rlo = prob->rlo_; |
| 70 | double *rup = prob->rup_; |
| 71 | double *sol = prob->sol_; |
| 72 | double *acts = prob->acts_; |
| 73 | |
| 74 | presolvehlink *clink = prob->clink_; |
| 75 | presolvehlink *rlink = prob->rlink_; |
| 76 | |
| 77 | action *actions = new action[nfcols+1]; |
| 78 | |
| 79 | # if PRESOLVE_DEBUG |
| 80 | std::cout << "Entering remove_fixed_action::presolve." << std::endl ; |
| 81 | presolve_check_sol(prob) ; |
| 82 | presolve_check_nbasic(prob) ; |
| 83 | # endif |
| 84 | |
| 85 | /* |
| 86 | Scan columns to be removed and total up the number of coefficients. |
| 87 | */ |
| 88 | int estsize=0; |
| 89 | int ckc; |
| 90 | for (ckc = 0 ; ckc < nfcols ; ckc++) { |
| 91 | int j = fcols[ckc]; |
| 92 | estsize += hincol[j]; |
| 93 | } |
| 94 | // Allocate arrays to hold coefficients and associated row indices |
| 95 | double * els_action = new double[estsize]; |
| 96 | int * rows_action = new int[estsize]; |
| 97 | int actsize=0; |
| 98 | // faster to do all deletes in row copy at once |
| 99 | int nrows = prob->nrows_; |
| 100 | CoinBigIndex * rstrt = new int[nrows+1]; |
| 101 | CoinZeroN(rstrt,nrows); |
| 102 | /* |
| 103 | Open a loop to excise each column a<j>. The first thing to do is load the |
| 104 | action entry with the index j, the value of x<j>, and the number of |
| 105 | entries in a<j>. After we walk the column and tweak the row-major |
| 106 | representation, we'll simply claim this column is empty by setting |
| 107 | hincol[j] = 0. |
| 108 | */ |
| 109 | for (ckc = 0 ; ckc < nfcols ; ckc++) { |
| 110 | int j = fcols[ckc]; |
| 111 | double solj = clo[j]; |
| 112 | CoinBigIndex kcs = mcstrt[j]; |
| 113 | CoinBigIndex kce = kcs + hincol[j]; |
| 114 | CoinBigIndex k; |
| 115 | |
| 116 | { action &f = actions[ckc]; |
| 117 | f.col = j; |
| 118 | f.sol = solj; |
| 119 | f.start = actsize; |
| 120 | } |
| 121 | /* |
| 122 | Now walk a<j>. For each row i with a coefficient a<ij> != 0: |
| 123 | * save the coefficient and row index, |
| 124 | * substitute the value of x<j>, adjusting the row bounds and lhs value |
| 125 | accordingly, then |
| 126 | * delete a<ij> from the row-major representation. |
| 127 | * Finally: mark the row as changed and add it to the list of rows to be |
| 128 | processed next. Then, for each remaining column in the row, do the same. |
| 129 | (It makes sense to put the columns on the `to be processed' list, but |
| 130 | I'm wondering about the wisdom of marking them as changed. |
| 131 | -- lh, 040824 -- ) |
| 132 | */ |
| 133 | for (k = kcs ; k < kce ; k++) { |
| 134 | int row = hrow[k]; |
| 135 | double coeff = colels[k]; |
| 136 | |
| 137 | els_action[actsize]=coeff; |
| 138 | rstrt[row]++; // increase counts |
| 139 | rows_action[actsize++]=row; |
| 140 | |
| 141 | // Avoid reducing finite infinity. |
| 142 | if (-PRESOLVE_INF < rlo[row]) |
| 143 | rlo[row] -= solj*coeff; |
| 144 | if (rup[row] < PRESOLVE_INF) |
| 145 | rup[row] -= solj*coeff; |
| 146 | if (sol) { |
| 147 | acts[row] -= solj*coeff; |
| 148 | } |
| 149 | #define TRY2 |
| 150 | #ifndef TRY2 |
| 151 | presolve_delete_from_row(row,j,mrstrt,hinrow,hcol,rowels); |
| 152 | if (hinrow[row] == 0) |
| 153 | { PRESOLVE_REMOVE_LINK(rlink,row) ; } |
| 154 | |
| 155 | // mark unless already marked |
| 156 | if (!prob->rowChanged(row)) { |
| 157 | prob->addRow(row); |
| 158 | CoinBigIndex krs = mrstrt[row]; |
| 159 | CoinBigIndex kre = krs + hinrow[row]; |
| 160 | for (CoinBigIndex k=krs; k<kre; k++) { |
| 161 | int jcol = hcol[k]; |
| 162 | prob->addCol(jcol); |
| 163 | } |
| 164 | } |
| 165 | #endif |
| 166 | } |
| 167 | /* |
| 168 | Remove the column's link from the linked list of columns, and declare |
| 169 | it empty in the column-major representation. Link removal must execute |
| 170 | even if the column is already of length 0 when it arrives. |
| 171 | */ |
| 172 | PRESOLVE_REMOVE_LINK(clink, j); |
| 173 | hincol[j] = 0; |
| 174 | } |
| 175 | /* |
| 176 | Set the actual end of the coefficient and row index arrays. |
| 177 | */ |
| 178 | actions[nfcols].start=actsize; |
| 179 | # if PRESOLVE_SUMMARY |
| 180 | printf("NFIXED: %d" , nfcols); |
| 181 | if (estsize-actsize > 0) |
| 182 | { printf(", overalloc %d" ,estsize-actsize) ; } |
| 183 | printf("\n" ) ; |
| 184 | # endif |
| 185 | // Now get columns by row |
| 186 | int * column = new int[actsize]; |
| 187 | int nel=0; |
| 188 | int iRow; |
| 189 | for (iRow=0;iRow<nrows;iRow++) { |
| 190 | int n=rstrt[iRow]; |
| 191 | rstrt[iRow]=nel; |
| 192 | nel += n; |
| 193 | } |
| 194 | rstrt[nrows]=nel; |
| 195 | for (ckc = 0 ; ckc < nfcols ; ckc++) { |
| 196 | int kcs = actions[ckc].start; |
| 197 | int j=actions[ckc].col; |
| 198 | int kce; |
| 199 | if (ckc<nfcols-1) |
| 200 | kce = actions[ckc+1].start; |
| 201 | else |
| 202 | kce = actsize; |
| 203 | for (int k=kcs;k<kce;k++) { |
| 204 | int iRow = rows_action[k]; |
| 205 | CoinBigIndex put = rstrt[iRow]; |
| 206 | rstrt[iRow]++; |
| 207 | column[put]=j; |
| 208 | } |
| 209 | } |
| 210 | // Now do rows |
| 211 | int ncols = prob->ncols_; |
| 212 | char * mark = new char[ncols]; |
| 213 | memset(mark,0,ncols); |
| 214 | // rstrts are now one out i.e. rstrt[0] is end of row 0 |
| 215 | nel=0; |
| 216 | #ifdef TRY2 |
| 217 | for (iRow=0;iRow<nrows;iRow++) { |
| 218 | int k; |
| 219 | for (k=nel;k<rstrt[iRow];k++) { |
| 220 | mark[column[k]]=1; |
| 221 | } |
| 222 | presolve_delete_many_from_major(iRow,mark,mrstrt,hinrow,hcol,rowels); |
| 223 | #ifndef NDEBUG |
| 224 | for (k=nel;k<rstrt[iRow];k++) { |
| 225 | assert(mark[column[k]]==0); |
| 226 | } |
| 227 | #endif |
| 228 | if (hinrow[iRow] == 0) |
| 229 | { |
| 230 | PRESOLVE_REMOVE_LINK(rlink,iRow) ; |
| 231 | } |
| 232 | // mark unless already marked |
| 233 | if (!prob->rowChanged(iRow)) { |
| 234 | prob->addRow(iRow); |
| 235 | CoinBigIndex krs = mrstrt[iRow]; |
| 236 | CoinBigIndex kre = krs + hinrow[iRow]; |
| 237 | for (CoinBigIndex k=krs; k<kre; k++) { |
| 238 | int jcol = hcol[k]; |
| 239 | prob->addCol(jcol); |
| 240 | } |
| 241 | } |
| 242 | nel=rstrt[iRow]; |
| 243 | } |
| 244 | #endif |
| 245 | delete [] mark; |
| 246 | delete [] column; |
| 247 | delete [] rstrt; |
| 248 | |
| 249 | # if PRESOLVE_DEBUG |
| 250 | presolve_check_sol(prob) ; |
| 251 | std::cout << "Leaving remove_fixed_action::presolve." << std::endl ; |
| 252 | # endif |
| 253 | |
| 254 | /* |
| 255 | Create the postsolve object, link it at the head of the list of postsolve |
| 256 | objects, and return a pointer. |
| 257 | */ |
| 258 | return (new remove_fixed_action(nfcols, |
| 259 | actions,els_action,rows_action,next)); |
| 260 | } |
| 261 | |
| 262 | |
| 263 | remove_fixed_action::remove_fixed_action(int nactions, |
| 264 | action *actions, |
| 265 | double * els_action, |
| 266 | int * rows_action, |
| 267 | const CoinPresolveAction *next) : |
| 268 | CoinPresolveAction(next), |
| 269 | colrows_(rows_action), |
| 270 | colels_(els_action), |
| 271 | nactions_(nactions), |
| 272 | actions_(actions) |
| 273 | { |
| 274 | } |
| 275 | |
| 276 | remove_fixed_action::~remove_fixed_action() |
| 277 | { |
| 278 | deleteAction(actions_,action*); |
| 279 | delete [] colels_; |
| 280 | delete [] colrows_; |
| 281 | } |
| 282 | |
| 283 | /* |
| 284 | * Say we determined that cup - clo <= ztolzb, so we fixed sol at clo. |
| 285 | * This involved subtracting clo*coeff from ub/lb for each row the |
| 286 | * variable occurred in. |
| 287 | * Now when we put the variable back in, by construction the variable |
| 288 | * is within tolerance, the non-slacks are unchanged, and the |
| 289 | * distances of the affected slacks from their bounds should remain |
| 290 | * unchanged (ignoring roundoff errors). |
| 291 | * It may be that by adding the term back in, the affected constraints |
| 292 | * now aren't as accurate due to round-off errors; this could happen |
| 293 | * if only one summand and the slack in the original formulation were large |
| 294 | * (and naturally had opposite signs), and the new term in the constraint |
| 295 | * is about the size of the old slack, so the new slack becomes about 0. |
| 296 | * It may be that there is catastrophic cancellation in the summation, |
| 297 | * so it might not compute to 0. |
| 298 | */ |
| 299 | void remove_fixed_action::postsolve(CoinPostsolveMatrix *prob) const |
| 300 | { |
| 301 | action * actions = actions_; |
| 302 | const int nactions = nactions_; |
| 303 | |
| 304 | double *colels = prob->colels_; |
| 305 | int *hrow = prob->hrow_; |
| 306 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 307 | int *hincol = prob->hincol_; |
| 308 | int *link = prob->link_; |
| 309 | CoinBigIndex &free_list = prob->free_list_; |
| 310 | |
| 311 | double *clo = prob->clo_; |
| 312 | double *cup = prob->cup_; |
| 313 | double *rlo = prob->rlo_; |
| 314 | double *rup = prob->rup_; |
| 315 | |
| 316 | double *sol = prob->sol_; |
| 317 | double *dcost = prob->cost_; |
| 318 | double *rcosts = prob->rcosts_; |
| 319 | |
| 320 | double *acts = prob->acts_; |
| 321 | double *rowduals = prob->rowduals_; |
| 322 | |
| 323 | unsigned char *colstat = prob->colstat_; |
| 324 | |
| 325 | const double maxmin = prob->maxmin_; |
| 326 | |
| 327 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
| 328 | char *cdone = prob->cdone_; |
| 329 | |
| 330 | std::cout << "Entering remove_fixed_action::postsolve." << std::endl ; |
| 331 | presolve_check_threads(prob) ; |
| 332 | presolve_check_free_list(prob) ; |
| 333 | presolve_check_sol(prob) ; |
| 334 | presolve_check_nbasic(prob) ; |
| 335 | # endif |
| 336 | |
| 337 | double * els_action = colels_; |
| 338 | int * rows_action = colrows_; |
| 339 | int end = actions[nactions].start; |
| 340 | |
| 341 | /* |
| 342 | At one point, it turned out that forcing_constraint_action was putting |
| 343 | duplicates in the column list it passed to remove_fixed_action. This is now |
| 344 | fixed, but ... it looks to me like we could be in trouble here if we |
| 345 | reinstate a column multiple times. Hence the assert. |
| 346 | */ |
| 347 | for (const action *f = &actions[nactions-1]; actions<=f; f--) { |
| 348 | int icol = f->col; |
| 349 | const double thesol = f->sol; |
| 350 | |
| 351 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
| 352 | assert(cdone[icol] != FIXED_VARIABLE) ; |
| 353 | cdone[icol] = FIXED_VARIABLE ; |
| 354 | # endif |
| 355 | |
| 356 | sol[icol] = thesol; |
| 357 | clo[icol] = thesol; |
| 358 | cup[icol] = thesol; |
| 359 | |
| 360 | int cs = NO_LINK ; |
| 361 | int start = f->start; |
| 362 | double dj = maxmin * dcost[icol]; |
| 363 | |
| 364 | for (int i=start; i<end; ++i) { |
| 365 | int row = rows_action[i]; |
| 366 | double coeff =els_action[i]; |
| 367 | |
| 368 | // pop free_list |
| 369 | CoinBigIndex k = free_list; |
| 370 | assert(k >= 0 && k < prob->bulk0_) ; |
| 371 | free_list = link[free_list]; |
| 372 | // restore |
| 373 | hrow[k] = row; |
| 374 | colels[k] = coeff; |
| 375 | link[k] = cs; |
| 376 | cs = k; |
| 377 | |
| 378 | if (-PRESOLVE_INF < rlo[row]) |
| 379 | rlo[row] += coeff * thesol; |
| 380 | if (rup[row] < PRESOLVE_INF) |
| 381 | rup[row] += coeff * thesol; |
| 382 | acts[row] += coeff * thesol; |
| 383 | |
| 384 | dj -= rowduals[row] * coeff; |
| 385 | } |
| 386 | |
| 387 | # if PRESOLVE_CONSISTENCY |
| 388 | presolve_check_free_list(prob) ; |
| 389 | # endif |
| 390 | |
| 391 | mcstrt[icol] = cs; |
| 392 | |
| 393 | rcosts[icol] = dj; |
| 394 | hincol[icol] = end-start; |
| 395 | end=start; |
| 396 | |
| 397 | /* Original comment: |
| 398 | * the bounds in the reduced problem were tightened. |
| 399 | * that means that this variable may not have been basic |
| 400 | * because it didn't have to be, |
| 401 | * but now it may have to. |
| 402 | * no - the bounds aren't changed by this operation |
| 403 | */ |
| 404 | /* |
| 405 | We've reintroduced the variable, but it's still fixed (equal bounds). |
| 406 | Pick the nonbasic status that agrees with the reduced cost. Later, if |
| 407 | postsolve unfixes the variable, we'll need to confirm that this status is |
| 408 | still viable. We live in a minimisation world here. |
| 409 | */ |
| 410 | if (colstat) |
| 411 | { if (dj < 0) |
| 412 | prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atUpperBound); |
| 413 | else |
| 414 | prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atLowerBound); } |
| 415 | |
| 416 | } |
| 417 | |
| 418 | |
| 419 | # if PRESOLVE_CONSISTENCY || PRESOLVE_DEBUG |
| 420 | presolve_check_threads(prob) ; |
| 421 | presolve_check_sol(prob) ; |
| 422 | presolve_check_nbasic(prob) ; |
| 423 | std::cout << "Leaving remove_fixed_action::postsolve." << std::endl ; |
| 424 | # endif |
| 425 | |
| 426 | return ; |
| 427 | } |
| 428 | |
| 429 | /* |
| 430 | Scan the problem for variables that are already fixed, and remove them. |
| 431 | There's an implicit assumption that the value of the variable is already |
| 432 | within bounds. If you want to protect against this possibility, you want to |
| 433 | use make_fixed. |
| 434 | */ |
| 435 | const CoinPresolveAction *remove_fixed (CoinPresolveMatrix *prob, |
| 436 | const CoinPresolveAction *next) |
| 437 | { |
| 438 | int ncols = prob->ncols_; |
| 439 | int *fcols = new int[ncols]; |
| 440 | int nfcols = 0; |
| 441 | |
| 442 | int *hincol = prob->hincol_; |
| 443 | |
| 444 | double *clo = prob->clo_; |
| 445 | double *cup = prob->cup_; |
| 446 | |
| 447 | for (int i = 0 ; i < ncols ; i++) |
| 448 | if (hincol[i] > 0 && clo[i] == cup[i]&&!prob->colProhibited2(i)) |
| 449 | fcols[nfcols++] = i; |
| 450 | |
| 451 | if (nfcols > 0) |
| 452 | { next = remove_fixed_action::presolve(prob, fcols, nfcols, next) ; } |
| 453 | delete[]fcols; |
| 454 | return (next); |
| 455 | } |
| 456 | |
| 457 | /* End routines associated with remove_fixed_action */ |
| 458 | |
| 459 | /* Begin routines associated with make_fixed_action */ |
| 460 | |
| 461 | const char *make_fixed_action::name() const |
| 462 | { |
| 463 | return ("make_fixed_action" ); |
| 464 | } |
| 465 | |
| 466 | |
| 467 | /* |
| 468 | This routine does the actual job of fixing one or more variables. The set |
| 469 | of indices to be fixed is specified by nfcols and fcols. fix_to_lower |
| 470 | specifies the bound where the variable(s) should be fixed. The other bound |
| 471 | is preserved as part of the action and the bounds are set equal. Note that |
| 472 | you don't get to specify the bound on a per-variable basis. |
| 473 | |
| 474 | If a primal solution is available, make_fixed_action will adjust the the |
| 475 | row activity to compensate for forcing the variable within bounds. If the |
| 476 | bounds are already equal, and the variable is within bounds, you should |
| 477 | consider remove_fixed_action. |
| 478 | */ |
| 479 | const CoinPresolveAction* |
| 480 | make_fixed_action::presolve (CoinPresolveMatrix *prob, |
| 481 | int *fcols, int nfcols, |
| 482 | bool fix_to_lower, |
| 483 | const CoinPresolveAction *next) |
| 484 | |
| 485 | { double *clo = prob->clo_; |
| 486 | double *cup = prob->cup_; |
| 487 | double *csol = prob->sol_; |
| 488 | |
| 489 | double *colels = prob->colels_; |
| 490 | int *hrow = prob->hrow_; |
| 491 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 492 | int *hincol = prob->hincol_; |
| 493 | |
| 494 | double *acts = prob->acts_; |
| 495 | |
| 496 | /* |
| 497 | Shouldn't happen, but ... |
| 498 | */ |
| 499 | if (nfcols <= 0) return (next) ; |
| 500 | |
| 501 | action *actions = new action[nfcols]; |
| 502 | |
| 503 | /* |
| 504 | Scan the set of indices specifying variables to be fixed. For each variable, |
| 505 | stash the unused bound in the action and set the bounds equal. If the client |
| 506 | has passed in a primal solution, update it if the value of the variable |
| 507 | changes. |
| 508 | */ |
| 509 | for (int ckc = 0 ; ckc < nfcols ; ckc++) |
| 510 | { int j = fcols[ckc] ; |
| 511 | double movement = 0 ; |
| 512 | |
| 513 | action &f = actions[ckc] ; |
| 514 | |
| 515 | f.col = j ; |
| 516 | if (fix_to_lower) { |
| 517 | f.bound = cup[j]; |
| 518 | cup[j] = clo[j]; |
| 519 | if (csol) { |
| 520 | movement = clo[j]-csol[j] ; |
| 521 | csol[j] = clo[j] ; |
| 522 | } |
| 523 | } else { |
| 524 | f.bound = clo[j]; |
| 525 | clo[j] = cup[j]; |
| 526 | if (csol) { |
| 527 | movement = cup[j]-csol[j]; |
| 528 | csol[j] = cup[j]; |
| 529 | } |
| 530 | } |
| 531 | if (movement) { |
| 532 | CoinBigIndex k; |
| 533 | for (k = mcstrt[j] ; k < mcstrt[j]+hincol[j] ; k++) { |
| 534 | int row = hrow[k]; |
| 535 | acts[row] += movement*colels[k]; |
| 536 | } |
| 537 | } |
| 538 | } |
| 539 | /* |
| 540 | Original comment: |
| 541 | This is unusual in that the make_fixed_action transform |
| 542 | contains within it a remove_fixed_action transform |
| 543 | bad idea? |
| 544 | |
| 545 | Explanatory comment: |
| 546 | Now that we've adjusted the bounds, time to create the postsolve action |
| 547 | that will restore the original bounds. But wait! We're not done. By calling |
| 548 | remove_fixed_action::presolve, we will remove these variables from the |
| 549 | model, caching the postsolve transform that will restore them inside the |
| 550 | postsolve transform for fixing the bounds. |
| 551 | */ |
| 552 | if (nfcols > 0) |
| 553 | { next = new make_fixed_action(nfcols, actions, fix_to_lower, |
| 554 | remove_fixed_action::presolve(prob,fcols, nfcols,0), |
| 555 | next) ; } |
| 556 | return (next) ; |
| 557 | } |
| 558 | |
| 559 | /* |
| 560 | Recall that in presolve, make_fixed_action forced a bound to fix a variable, |
| 561 | then called remove_fixed_action to empty the column. removed_fixed_action |
| 562 | left a postsolve object hanging off faction_, and our first act here is to |
| 563 | call r_f_a::postsolve to repopulate the columns. The m_f_a postsolve activity |
| 564 | consists of relaxing one of the bounds and making sure that the status is |
| 565 | still viable (we can potentially eliminate the bound here). |
| 566 | */ |
| 567 | void make_fixed_action::postsolve(CoinPostsolveMatrix *prob) const |
| 568 | { |
| 569 | const action *const actions = actions_; |
| 570 | const int nactions = nactions_; |
| 571 | const bool fix_to_lower = fix_to_lower_; |
| 572 | |
| 573 | double *clo = prob->clo_; |
| 574 | double *cup = prob->cup_; |
| 575 | double *sol = prob->sol_ ; |
| 576 | unsigned char *colstat = prob->colstat_; |
| 577 | /* |
| 578 | Repopulate the columns. |
| 579 | */ |
| 580 | assert(nactions == faction_->nactions_) ; |
| 581 | faction_->postsolve(prob); |
| 582 | /* |
| 583 | Walk the actions: restore each bound and check that the status is still |
| 584 | appropriate. Given that we're unfixing a fixed variable, it's safe to assume |
| 585 | that the unaffected bound is finite. |
| 586 | */ |
| 587 | for (int cnt = nactions-1 ; cnt >= 0 ; cnt--) |
| 588 | { const action *f = &actions[cnt]; |
| 589 | int icol = f->col; |
| 590 | double xj = sol[icol] ; |
| 591 | |
| 592 | assert(faction_->actions_[cnt].col == icol) ; |
| 593 | |
| 594 | if (fix_to_lower) |
| 595 | { double ub = f->bound ; |
| 596 | cup[icol] = ub ; |
| 597 | if (colstat) |
| 598 | { if (ub >= PRESOLVE_INF || xj != ub) |
| 599 | { prob->setColumnStatus(icol, |
| 600 | CoinPrePostsolveMatrix::atLowerBound) ; } } } |
| 601 | else |
| 602 | { double lb = f->bound ; |
| 603 | clo[icol] = lb ; |
| 604 | if (colstat) |
| 605 | { if (lb <= -PRESOLVE_INF || xj != lb) |
| 606 | { prob->setColumnStatus(icol, |
| 607 | CoinPrePostsolveMatrix::atUpperBound) ; } } } } |
| 608 | |
| 609 | # if PRESOLVE_CONSISTENCY || PRESOLVE_DEBUG |
| 610 | presolve_check_threads(prob) ; |
| 611 | presolve_check_sol(prob) ; |
| 612 | presolve_check_nbasic(prob) ; |
| 613 | std::cout << "Leaving make_fixed_action::postsolve." << std::endl ; |
| 614 | # endif |
| 615 | return ; } |
| 616 | |
| 617 | /*! |
| 618 | Scan the columns and collect indices of columns that have upper and lower |
| 619 | bounds within the zero tolerance of one another. Hand this list to |
| 620 | make_fixed_action::presolve() to do the heavy lifting. |
| 621 | |
| 622 | make_fixed_action will compensate for variables which are infeasible, forcing |
| 623 | them to feasibility and correcting the row activity, before invoking |
| 624 | remove_fixed_action to remove the variable from the problem. If you're |
| 625 | confident of feasibility, consider remove_fixed. |
| 626 | */ |
| 627 | const CoinPresolveAction *make_fixed (CoinPresolveMatrix *prob, |
| 628 | const CoinPresolveAction *next) |
| 629 | { |
| 630 | int ncols = prob->ncols_; |
| 631 | int *fcols = new int[ncols]; |
| 632 | int nfcols = 0; |
| 633 | |
| 634 | int *hincol = prob->hincol_; |
| 635 | |
| 636 | double *clo = prob->clo_; |
| 637 | double *cup = prob->cup_; |
| 638 | |
| 639 | for (int i = 0 ; i < ncols ; i++) |
| 640 | { if (hincol[i] > 0 && |
| 641 | fabs(cup[i] - clo[i]) < ZTOLDP && !prob->colProhibited2(i)) |
| 642 | { fcols[nfcols++] = i ; } } |
| 643 | |
| 644 | /* |
| 645 | Call m_f_a::presolve to do the heavy lifting. This will create a new |
| 646 | CoinPresolveAction, which will become the head of the list of |
| 647 | CoinPresolveAction's currently pointed to by next. |
| 648 | */ |
| 649 | next = make_fixed_action::presolve(prob,fcols,nfcols,true,next) ; |
| 650 | |
| 651 | delete[]fcols ; |
| 652 | return (next) ; } |
| 653 | // Transfers costs |
| 654 | void |
| 655 | transferCosts(CoinPresolveMatrix * prob) |
| 656 | { |
| 657 | double *colels = prob->colels_; |
| 658 | int *hrow = prob->hrow_; |
| 659 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 660 | int *hincol = prob->hincol_; |
| 661 | |
| 662 | double *rowels = prob->rowels_; |
| 663 | int *hcol = prob->hcol_; |
| 664 | CoinBigIndex *mrstrt = prob->mrstrt_; |
| 665 | int *hinrow = prob->hinrow_; |
| 666 | |
| 667 | double *rlo = prob->rlo_; |
| 668 | double *rup = prob->rup_; |
| 669 | double *clo = prob->clo_; |
| 670 | double *cup = prob->cup_; |
| 671 | int ncols = prob->ncols_; |
| 672 | double *dcost = prob->cost_; |
| 673 | unsigned char * integerType = prob->integerType_; |
| 674 | double bias = prob->dobias_; |
| 675 | int icol; |
| 676 | int numberIntegers=0; |
| 677 | for (icol=0;icol<ncols;icol++) { |
| 678 | if (integerType[icol]) |
| 679 | numberIntegers++; |
| 680 | } |
| 681 | int nchanged=0; |
| 682 | for (icol=0;icol<ncols;icol++) { |
| 683 | if (dcost[icol]&&hincol[icol]==1&&cup[icol]>clo[icol]) { |
| 684 | int irow=hrow[mcstrt[icol]]; |
| 685 | if (rlo[irow]==rup[irow]) { |
| 686 | // transfer costs so can be made slack |
| 687 | double ratio = dcost[icol]/colels[mcstrt[icol]]; |
| 688 | bias += rlo[irow]*ratio; |
| 689 | for (CoinBigIndex j=mrstrt[irow];j<mrstrt[irow]+hinrow[irow];j++) { |
| 690 | int jcol = hcol[j]; |
| 691 | double value = rowels[j]; |
| 692 | dcost[jcol] -= ratio*value; |
| 693 | } |
| 694 | dcost[icol]=0.0; |
| 695 | nchanged++; |
| 696 | } |
| 697 | } |
| 698 | } |
| 699 | //if (nchanged) |
| 700 | //printf("%d singleton columns have transferred costs\n",nchanged); |
| 701 | if (numberIntegers) { |
| 702 | int changed=-1; |
| 703 | while (changed) { |
| 704 | changed=0; |
| 705 | for (icol=0;icol<ncols;icol++) { |
| 706 | if (dcost[icol]&&cup[icol]>clo[icol]) { |
| 707 | for (CoinBigIndex k=mcstrt[icol];k<mcstrt[icol]+hincol[icol];k++) { |
| 708 | int irow=hrow[k]; |
| 709 | if (rlo[irow]==rup[irow]) { |
| 710 | // See if can give more integer variables costs |
| 711 | CoinBigIndex j; |
| 712 | int nNow = integerType[icol] ? 1 : 0; |
| 713 | int nThen=0; |
| 714 | for (j=mrstrt[irow];j<mrstrt[irow]+hinrow[irow];j++) { |
| 715 | int jcol = hcol[j]; |
| 716 | if (!dcost[jcol]&&integerType[jcol]) |
| 717 | nThen++; |
| 718 | } |
| 719 | if (nThen>nNow) { |
| 720 | // transfer costs so can be made slack |
| 721 | double ratio = dcost[icol]/colels[mcstrt[icol]]; |
| 722 | bias += rlo[irow]*ratio; |
| 723 | for (j=mrstrt[irow];j<mrstrt[irow]+hinrow[irow];j++) { |
| 724 | int jcol = hcol[j]; |
| 725 | double value = rowels[j]; |
| 726 | dcost[jcol] -= ratio*value; |
| 727 | } |
| 728 | dcost[icol]=0.0; |
| 729 | changed++; |
| 730 | break; |
| 731 | } |
| 732 | } |
| 733 | } |
| 734 | } |
| 735 | } |
| 736 | if (changed) { |
| 737 | nchanged+=changed; |
| 738 | //printf("%d changed this pass\n",changed); |
| 739 | } |
| 740 | } |
| 741 | } |
| 742 | //if (bias!=prob->dobias_) |
| 743 | //printf("new bias %g\n",bias); |
| 744 | prob->dobias_ = bias; |
| 745 | } |
| 746 | |