| 1 | /* $Id: CoinPresolveEmpty.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" |
| 14 | #include "CoinMessage.hpp" |
| 15 | |
| 16 | #if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
| 17 | #include "CoinPresolvePsdebug.hpp" |
| 18 | #endif |
| 19 | |
| 20 | |
| 21 | /* \file |
| 22 | |
| 23 | Routines to remove/reinsert empty columns and rows. |
| 24 | */ |
| 25 | |
| 26 | |
| 27 | /* |
| 28 | Physically remove empty columns, compressing mcstrt and hincol. The major |
| 29 | side effect is that columns are renumbered, thus clink_ is no longer valid |
| 30 | and must be rebuilt. |
| 31 | |
| 32 | It's necessary to rebuild clink_ in order to do direct conversion of a |
| 33 | CoinPresolveMatrix to a CoinPostsolveMatrix by transferring the data arrays. |
| 34 | Without clink_, it's impractical to build link_ to match the transferred bulk |
| 35 | storage. |
| 36 | */ |
| 37 | const CoinPresolveAction |
| 38 | *drop_empty_cols_action::presolve (CoinPresolveMatrix *prob, |
| 39 | int *ecols, |
| 40 | int necols, |
| 41 | const CoinPresolveAction *next) |
| 42 | { |
| 43 | int ncols = prob->ncols_; |
| 44 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 45 | int *hincol = prob->hincol_; |
| 46 | |
| 47 | presolvehlink *clink = prob->clink_; |
| 48 | |
| 49 | double *clo = prob->clo_; |
| 50 | double *cup = prob->cup_; |
| 51 | double *dcost = prob->cost_; |
| 52 | |
| 53 | const double ztoldj = prob->ztoldj_; |
| 54 | |
| 55 | unsigned char * integerType = prob->integerType_; |
| 56 | int * originalColumn = prob->originalColumn_; |
| 57 | |
| 58 | const double maxmin = prob->maxmin_; |
| 59 | |
| 60 | double * sol = prob->sol_; |
| 61 | unsigned char * colstat = prob->colstat_; |
| 62 | |
| 63 | action *actions = new action[necols]; |
| 64 | int * colmapping = new int [ncols+1]; |
| 65 | bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; |
| 66 | |
| 67 | CoinZeroN(colmapping,ncols); |
| 68 | int i; |
| 69 | for (i=necols-1; i>=0; i--) { |
| 70 | int jcol = ecols[i]; |
| 71 | colmapping[jcol]=-1; |
| 72 | action &e = actions[i]; |
| 73 | |
| 74 | e.jcol = jcol; |
| 75 | e.clo = clo[jcol]; |
| 76 | e.cup = cup[jcol]; |
| 77 | // adjust if integer |
| 78 | if (integerType[jcol]) { |
| 79 | e.clo = ceil(e.clo-1.0e-9); |
| 80 | e.cup = floor(e.cup+1.0e-9); |
| 81 | if (e.clo>e.cup&&!fixInfeasibility) { |
| 82 | // infeasible |
| 83 | prob->status_|= 1; |
| 84 | prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, |
| 85 | prob->messages()) |
| 86 | <<jcol |
| 87 | <<e.clo |
| 88 | <<e.cup |
| 89 | <<CoinMessageEol; |
| 90 | } |
| 91 | } |
| 92 | e.cost = dcost[jcol]; |
| 93 | |
| 94 | // there are no more constraints on this variable, |
| 95 | // so we had better be able to compute the answer now |
| 96 | if (fabs(dcost[jcol])<ztoldj) |
| 97 | dcost[jcol]=0.0; |
| 98 | if (dcost[jcol] * maxmin == 0.0) { |
| 99 | // hopefully, we can make this non-basic |
| 100 | // what does OSL currently do in this case??? |
| 101 | e.sol = (-PRESOLVE_INF < e.clo |
| 102 | ? e.clo |
| 103 | : e.cup < PRESOLVE_INF |
| 104 | ? e.cup |
| 105 | : 0.0); |
| 106 | } else if (dcost[jcol] * maxmin > 0.0) { |
| 107 | if (-PRESOLVE_INF < e.clo) |
| 108 | e.sol = e.clo; |
| 109 | else { |
| 110 | prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDB, |
| 111 | prob->messages()) |
| 112 | <<jcol |
| 113 | <<CoinMessageEol; |
| 114 | prob->status_ |= 2; |
| 115 | break; |
| 116 | } |
| 117 | } else { |
| 118 | if (e.cup < PRESOLVE_INF) |
| 119 | e.sol = e.cup; |
| 120 | else { |
| 121 | prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDA, |
| 122 | prob->messages()) |
| 123 | <<jcol |
| 124 | <<CoinMessageEol; |
| 125 | prob->status_ |= 2; |
| 126 | break; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | #if PRESOLVE_DEBUG |
| 131 | if (e.sol * dcost[jcol]) { |
| 132 | //printf("\a>>>NON-ZERO COST FOR EMPTY COL %d: %g\n", jcol, dcost[jcol]); |
| 133 | } |
| 134 | #endif |
| 135 | prob->change_bias(e.sol * dcost[jcol]); |
| 136 | |
| 137 | |
| 138 | } |
| 139 | int ncols2=0; |
| 140 | |
| 141 | // now move remaining ones down |
| 142 | for (i=0;i<ncols;i++) { |
| 143 | if (!colmapping[i]) { |
| 144 | mcstrt[ncols2] = mcstrt[i]; |
| 145 | hincol[ncols2] = hincol[i]; |
| 146 | |
| 147 | clo[ncols2] = clo[i]; |
| 148 | cup[ncols2] = cup[i]; |
| 149 | |
| 150 | dcost[ncols2] = dcost[i]; |
| 151 | if (sol) { |
| 152 | sol[ncols2] = sol[i]; |
| 153 | colstat[ncols2] = colstat[i]; |
| 154 | } |
| 155 | |
| 156 | integerType[ncols2] = integerType[i]; |
| 157 | originalColumn[ncols2] = originalColumn[i]; |
| 158 | colmapping[i] = ncols2++; |
| 159 | } |
| 160 | } |
| 161 | mcstrt[ncols2] = mcstrt[ncols] ; |
| 162 | colmapping[ncols] = ncols2 ; |
| 163 | /* |
| 164 | Rebuild clink_. At this point, all empty columns are linked out, so the |
| 165 | only columns left are columns that are to be saved, hence available in |
| 166 | colmapping. All we need to do is walk clink_ and write the new entries |
| 167 | into a new array. |
| 168 | */ |
| 169 | |
| 170 | { presolvehlink *newclink = new presolvehlink [ncols2+1] ; |
| 171 | for (int oldj = ncols ; oldj >= 0 ; oldj = clink[oldj].pre) |
| 172 | { presolvehlink &oldlnk = clink[oldj] ; |
| 173 | int newj = colmapping[oldj] ; |
| 174 | assert(newj >= 0 && newj <= ncols2) ; |
| 175 | presolvehlink &newlnk = newclink[newj] ; |
| 176 | if (oldlnk.suc >= 0) |
| 177 | { newlnk.suc = colmapping[oldlnk.suc] ; } |
| 178 | else |
| 179 | { newlnk.suc = NO_LINK ; } |
| 180 | if (oldlnk.pre >= 0) |
| 181 | { newlnk.pre = colmapping[oldlnk.pre] ; } |
| 182 | else |
| 183 | { newlnk.pre = NO_LINK ; } } |
| 184 | delete [] clink ; |
| 185 | prob->clink_ = newclink ; } |
| 186 | |
| 187 | delete [] colmapping; |
| 188 | prob->ncols_ = ncols2; |
| 189 | |
| 190 | return (new drop_empty_cols_action(necols, actions, next)); |
| 191 | } |
| 192 | |
| 193 | |
| 194 | const CoinPresolveAction *drop_empty_cols_action::presolve(CoinPresolveMatrix *prob, |
| 195 | const CoinPresolveAction *next) |
| 196 | { |
| 197 | const int *hincol = prob->hincol_; |
| 198 | // const double *clo = prob->clo_; |
| 199 | // const double *cup = prob->cup_; |
| 200 | int ncols = prob->ncols_; |
| 201 | int i; |
| 202 | int nempty = 0; |
| 203 | int * empty = new int [ncols]; |
| 204 | CoinBigIndex nelems2 = 0 ; |
| 205 | |
| 206 | // count empty cols |
| 207 | for (i=0; i<ncols; i++) |
| 208 | { nelems2 += hincol[i] ; |
| 209 | if (hincol[i] == 0) { |
| 210 | #if PRESOLVE_DEBUG |
| 211 | if (nempty==0) |
| 212 | printf("UNUSED COLS: " ); |
| 213 | else |
| 214 | if (i < 100 && nempty%25 == 0) |
| 215 | printf("\n" ) ; |
| 216 | else |
| 217 | if (i >= 100 && i < 1000 && nempty%19 == 0) |
| 218 | printf("\n" ) ; |
| 219 | else |
| 220 | if (i >= 1000 && nempty%15 == 0) |
| 221 | printf("\n" ) ; |
| 222 | printf("%d " , i); |
| 223 | #endif |
| 224 | empty[nempty++] = i; |
| 225 | } |
| 226 | } |
| 227 | prob->nelems_ = nelems2 ; |
| 228 | |
| 229 | if (nempty) { |
| 230 | #if PRESOLVE_DEBUG |
| 231 | printf("\ndropped %d cols\n" , nempty); |
| 232 | #endif |
| 233 | next = drop_empty_cols_action::presolve(prob, empty, nempty, next); |
| 234 | } |
| 235 | delete [] empty; |
| 236 | return (next); |
| 237 | } |
| 238 | |
| 239 | |
| 240 | void drop_empty_cols_action::postsolve(CoinPostsolveMatrix *prob) const |
| 241 | { |
| 242 | const int nactions = nactions_; |
| 243 | const action *const actions = actions_; |
| 244 | |
| 245 | int ncols = prob->ncols_; |
| 246 | |
| 247 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 248 | int *hincol = prob->hincol_; |
| 249 | // int *hrow = prob->hrow_; |
| 250 | |
| 251 | double *clo = prob->clo_; |
| 252 | double *cup = prob->cup_; |
| 253 | |
| 254 | double *sol = prob->sol_; |
| 255 | double *cost = prob->cost_; |
| 256 | double *rcosts = prob->rcosts_; |
| 257 | unsigned char *colstat = prob->colstat_; |
| 258 | const double maxmin = prob->maxmin_; |
| 259 | |
| 260 | int ncols2 = ncols+nactions; |
| 261 | int * colmapping = new int [ncols2]; |
| 262 | |
| 263 | CoinZeroN(colmapping,ncols2); |
| 264 | # if PRESOLVE_DEBUG |
| 265 | char *cdone = prob->cdone_; |
| 266 | # endif |
| 267 | int action_i; |
| 268 | for (action_i = 0; action_i < nactions; action_i++) { |
| 269 | const action *e = &actions[action_i]; |
| 270 | int jcol = e->jcol; |
| 271 | colmapping[jcol]=-1; |
| 272 | } |
| 273 | |
| 274 | int i; |
| 275 | |
| 276 | // now move remaining ones up |
| 277 | for (i=ncols2-1;i>=0;i--) { |
| 278 | if (!colmapping[i]) { |
| 279 | ncols--; |
| 280 | mcstrt[i] = mcstrt[ncols]; |
| 281 | hincol[i] = hincol[ncols]; |
| 282 | |
| 283 | clo[i] = clo[ncols]; |
| 284 | cup[i] = cup[ncols]; |
| 285 | |
| 286 | cost[i] = cost[ncols]; |
| 287 | |
| 288 | if (sol) |
| 289 | sol[i] = sol[ncols]; |
| 290 | |
| 291 | if (rcosts) |
| 292 | rcosts[i] = rcosts[ncols]; |
| 293 | |
| 294 | if (colstat) |
| 295 | colstat[i] = colstat[ncols]; |
| 296 | # if PRESOLVE_DEBUG |
| 297 | cdone[i] = cdone[ncols]; |
| 298 | # endif |
| 299 | } |
| 300 | } |
| 301 | assert (!ncols); |
| 302 | |
| 303 | delete [] colmapping; |
| 304 | |
| 305 | for (action_i = 0; action_i < nactions; action_i++) { |
| 306 | const action *e = &actions[action_i]; |
| 307 | int jcol = e->jcol; |
| 308 | |
| 309 | // now recreate jcol |
| 310 | clo[jcol] = e->clo; |
| 311 | cup[jcol] = e->cup; |
| 312 | if (sol) |
| 313 | sol[jcol] = e->sol; |
| 314 | cost[jcol] = e->cost; |
| 315 | |
| 316 | if (rcosts) |
| 317 | rcosts[jcol] = maxmin*cost[jcol]; |
| 318 | |
| 319 | hincol[jcol] = 0; |
| 320 | mcstrt[jcol] = NO_LINK ; |
| 321 | # if PRESOLVE_DEBUG |
| 322 | cdone[jcol] = DROP_COL; |
| 323 | # endif |
| 324 | if (colstat) |
| 325 | prob->setColumnStatusUsingValue(jcol); |
| 326 | } |
| 327 | |
| 328 | prob->ncols_ += nactions; |
| 329 | |
| 330 | # if PRESOLVE_CONSISTENCY |
| 331 | presolve_check_threads(prob) ; |
| 332 | # endif |
| 333 | |
| 334 | } |
| 335 | |
| 336 | |
| 337 | |
| 338 | const CoinPresolveAction *drop_empty_rows_action::presolve(CoinPresolveMatrix *prob, |
| 339 | const CoinPresolveAction *next) |
| 340 | { |
| 341 | int ncols = prob->ncols_; |
| 342 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 343 | int *hincol = prob->hincol_; |
| 344 | int *hrow = prob->hrow_; |
| 345 | |
| 346 | int nrows = prob->nrows_; |
| 347 | // This is done after row copy needed |
| 348 | //int *mrstrt = prob->mrstrt_; |
| 349 | int *hinrow = prob->hinrow_; |
| 350 | //int *hcol = prob->hcol_; |
| 351 | |
| 352 | double *rlo = prob->rlo_; |
| 353 | double *rup = prob->rup_; |
| 354 | |
| 355 | unsigned char *rowstat = prob->rowstat_; |
| 356 | double *acts = prob->acts_; |
| 357 | int * originalRow = prob->originalRow_; |
| 358 | |
| 359 | //presolvehlink *rlink = prob->rlink_; |
| 360 | bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; |
| 361 | // Relax tolerance |
| 362 | double tolerance = 10.0*prob->feasibilityTolerance_; |
| 363 | |
| 364 | |
| 365 | int i; |
| 366 | int nactions = 0; |
| 367 | for (i=0; i<nrows; i++) |
| 368 | if (hinrow[i] == 0) |
| 369 | nactions++; |
| 370 | |
| 371 | if (nactions == 0) |
| 372 | return next; |
| 373 | else { |
| 374 | action *actions = new action[nactions]; |
| 375 | int * rowmapping = new int [nrows]; |
| 376 | |
| 377 | nactions = 0; |
| 378 | int nrows2=0; |
| 379 | for (i=0; i<nrows; i++) { |
| 380 | if (hinrow[i] == 0) { |
| 381 | action &e = actions[nactions]; |
| 382 | |
| 383 | # if PRESOLVE_DEBUG |
| 384 | if (nactions == 0) |
| 385 | printf("UNUSED ROWS: " ); |
| 386 | else |
| 387 | if (i < 100 && nactions%25 == 0) |
| 388 | printf("\n" ) ; |
| 389 | else |
| 390 | if (i >= 100 && i < 1000 && nactions%19 == 0) |
| 391 | printf("\n" ) ; |
| 392 | else |
| 393 | if (i >= 1000 && nactions%15 == 0) |
| 394 | printf("\n" ) ; |
| 395 | printf("%d " , i); |
| 396 | # endif |
| 397 | |
| 398 | nactions++; |
| 399 | if (rlo[i] > 0.0 || rup[i] < 0.0) { |
| 400 | if ((rlo[i]<=tolerance && |
| 401 | rup[i]>=-tolerance)||fixInfeasibility) { |
| 402 | rlo[i]=0.0; |
| 403 | rup[i]=0.0; |
| 404 | } else { |
| 405 | prob->status_|= 1; |
| 406 | prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, |
| 407 | prob->messages()) |
| 408 | <<i |
| 409 | <<rlo[i] |
| 410 | <<rup[i] |
| 411 | <<CoinMessageEol; |
| 412 | break; |
| 413 | } |
| 414 | } |
| 415 | e.row = i; |
| 416 | e.rlo = rlo[i]; |
| 417 | e.rup = rup[i]; |
| 418 | rowmapping[i]=-1; |
| 419 | |
| 420 | } else { |
| 421 | // move down - we want to preserve order |
| 422 | rlo[nrows2]=rlo[i]; |
| 423 | rup[nrows2]=rup[i]; |
| 424 | originalRow[nrows2]=i; |
| 425 | if (acts) { |
| 426 | acts[nrows2]=acts[i]; |
| 427 | rowstat[nrows2]=rowstat[i]; |
| 428 | } |
| 429 | rowmapping[i]=nrows2++; |
| 430 | } |
| 431 | } |
| 432 | |
| 433 | // remap matrix |
| 434 | for (i=0;i<ncols;i++) { |
| 435 | int j; |
| 436 | for (j=mcstrt[i];j<mcstrt[i]+hincol[i];j++) |
| 437 | hrow[j] = rowmapping[hrow[j]]; |
| 438 | } |
| 439 | delete [] rowmapping; |
| 440 | |
| 441 | prob->nrows_ = nrows2; |
| 442 | |
| 443 | #if PRESOLVE_DEBUG |
| 444 | presolve_check_nbasic(prob) ; |
| 445 | if (nactions) |
| 446 | printf("\ndropped %d rows\n" , nactions); |
| 447 | #endif |
| 448 | return (new drop_empty_rows_action(nactions, actions, next)); |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | void drop_empty_rows_action::postsolve(CoinPostsolveMatrix *prob) const |
| 453 | { |
| 454 | const int nactions = nactions_; |
| 455 | const action *const actions = actions_; |
| 456 | |
| 457 | int ncols = prob->ncols_; |
| 458 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 459 | int *hincol = prob->hincol_; |
| 460 | |
| 461 | int *hrow = prob->hrow_; |
| 462 | |
| 463 | double *rlo = prob->rlo_; |
| 464 | double *rup = prob->rup_; |
| 465 | unsigned char *rowstat = prob->rowstat_; |
| 466 | double *rowduals = prob->rowduals_; |
| 467 | double *acts = prob->acts_; |
| 468 | # if PRESOLVE_DEBUG |
| 469 | char *rdone = prob->rdone_; |
| 470 | # endif |
| 471 | |
| 472 | int nrows0 = prob->nrows0_; |
| 473 | int nrows = prob->nrows_; |
| 474 | |
| 475 | int * rowmapping = new int [nrows0]; |
| 476 | CoinZeroN(rowmapping,nrows0) ; |
| 477 | |
| 478 | int i, action_i; |
| 479 | for (action_i = 0; action_i<nactions; action_i++) { |
| 480 | const action *e = &actions[action_i]; |
| 481 | int hole = e->row; |
| 482 | rowmapping[hole]=-1; |
| 483 | } |
| 484 | |
| 485 | // move data |
| 486 | for (i=nrows0-1; i>=0; i--) { |
| 487 | if (!rowmapping[i]) { |
| 488 | // not a hole |
| 489 | nrows--; |
| 490 | rlo[i]=rlo[nrows]; |
| 491 | rup[i]=rup[nrows]; |
| 492 | acts[i]=acts[nrows]; |
| 493 | rowduals[i]=rowduals[nrows]; |
| 494 | if (rowstat) |
| 495 | rowstat[i] = rowstat[nrows]; |
| 496 | # if PRESOLVE_DEBUG |
| 497 | rdone[i] = rdone[nrows] ; |
| 498 | # endif |
| 499 | } |
| 500 | } |
| 501 | assert (!nrows); |
| 502 | // set up mapping for matrix |
| 503 | for (i=0;i<nrows0;i++) { |
| 504 | if (!rowmapping[i]) |
| 505 | rowmapping[nrows++]=i; |
| 506 | } |
| 507 | |
| 508 | for (int j=0; j<ncols; j++) { |
| 509 | CoinBigIndex start = mcstrt[j]; |
| 510 | CoinBigIndex end = start + hincol[j]; |
| 511 | |
| 512 | for (CoinBigIndex k=start; k<end; ++k) { |
| 513 | hrow[k] = rowmapping[hrow[k]]; |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | |
| 518 | delete [] rowmapping; |
| 519 | |
| 520 | for (action_i = 0; action_i < nactions; action_i++) { |
| 521 | const action *e = &actions[action_i]; |
| 522 | int irow = e->row; |
| 523 | |
| 524 | // Now recreate irow |
| 525 | rlo[irow] = e->rlo; |
| 526 | rup[irow] = e->rup; |
| 527 | |
| 528 | if (rowstat) |
| 529 | prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic); |
| 530 | rowduals[irow] = 0.0; // ??? |
| 531 | acts[irow] = 0.0; |
| 532 | |
| 533 | # if PRESOLVE_DEBUG |
| 534 | rdone[irow] = DROP_ROW; |
| 535 | # endif |
| 536 | } |
| 537 | |
| 538 | prob->nrows_ = prob->nrows_+nactions; |
| 539 | |
| 540 | # if PRESOLVE_DEBUG |
| 541 | presolve_check_threads(prob) ; |
| 542 | # endif |
| 543 | |
| 544 | } |
| 545 | |