| 1 | /* $Id: CoinPresolveDual.cpp 1373 2011-01-03 23:57:44Z lou $ */ |
| 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 "CoinPresolveDual.hpp" |
| 12 | #include "CoinMessage.hpp" |
| 13 | #include "CoinHelperFunctions.hpp" |
| 14 | #include "CoinFloatEqual.hpp" |
| 15 | //#define PRESOLVE_TIGHTEN_DUALS 1 |
| 16 | //#define PRESOLVE_DEBUG 1 |
| 17 | |
| 18 | #ifdef PRESOLVE_DEBUG |
| 19 | #include "CoinPresolvePsdebug.hpp" |
| 20 | #endif |
| 21 | |
| 22 | // this looks for "dominated columns" |
| 23 | // following ekkredc |
| 24 | // rdmin == dwrow2 |
| 25 | // rdmax == dwrow |
| 26 | // this transformation is applied in: k4.mps, lp22.mps |
| 27 | |
| 28 | // make inferences using this constraint on reduced cost: |
| 29 | // at optimality dj>0 ==> var must be at lb |
| 30 | // dj<0 ==> var must be at ub |
| 31 | // |
| 32 | // This implies: |
| 33 | // there is no lb ==> dj<=0 at optimality |
| 34 | // there is no ub ==> dj>=0 at optimality |
| 35 | |
| 36 | /* |
| 37 | This routine looks to be something of a work in progres. See the comment |
| 38 | that begins with `Gack!'. And down in the bound propagation loop, why do we |
| 39 | only work with variables with u_j = infty? The corresponding section of code |
| 40 | for l_j = -infty is ifdef'd away. And why exclude the code protected by |
| 41 | PRESOLVE_TIGHTEN_DUALS? And why are we using ekkinf instead of PRESOLVE_INF? |
| 42 | |
| 43 | There is no postsolve action because once we've identified a variable to fix |
| 44 | we can invoke make_fixed_action. |
| 45 | */ |
| 46 | const CoinPresolveAction *remove_dual_action::presolve(CoinPresolveMatrix *prob, |
| 47 | const CoinPresolveAction *next) |
| 48 | { |
| 49 | double startTime = 0.0; |
| 50 | int startEmptyRows=0; |
| 51 | int startEmptyColumns = 0; |
| 52 | if (prob->tuning_) { |
| 53 | startTime = CoinCpuTime(); |
| 54 | startEmptyRows = prob->countEmptyRows(); |
| 55 | startEmptyColumns = prob->countEmptyCols(); |
| 56 | } |
| 57 | double *colels = prob->colels_; |
| 58 | int *hrow = prob->hrow_; |
| 59 | CoinBigIndex *mcstrt = prob->mcstrt_; |
| 60 | int *hincol = prob->hincol_; |
| 61 | int ncols = prob->ncols_; |
| 62 | |
| 63 | double *clo = prob->clo_; |
| 64 | double *cup = prob->cup_; |
| 65 | unsigned char *colstat = prob->colstat_ ; |
| 66 | |
| 67 | // Used only in `fix if simple' section below. Remove dec'l to avoid |
| 68 | // GCC compile warning. |
| 69 | // double *rowels = prob->rowels_; |
| 70 | int *hcol = prob->hcol_; |
| 71 | CoinBigIndex *mrstrt = prob->mrstrt_; |
| 72 | int *hinrow = prob->hinrow_; |
| 73 | double *csol = prob->sol_; |
| 74 | int nrows = prob->nrows_; |
| 75 | |
| 76 | double *rlo = prob->rlo_; |
| 77 | double *rup = prob->rup_; |
| 78 | |
| 79 | double *dcost = prob->cost_; |
| 80 | const unsigned char *integerType = prob->integerType_; |
| 81 | |
| 82 | const double maxmin = prob->maxmin_; |
| 83 | |
| 84 | const double ekkinf = 1e28; |
| 85 | const double ekkinf2 = 1e20; |
| 86 | const double ztoldj = prob->ztoldj_; |
| 87 | |
| 88 | CoinRelFltEq relEq(prob->ztolzb_) ; |
| 89 | |
| 90 | double *rdmin = prob->usefulRowDouble_; //new double[nrows]; |
| 91 | double *rdmax = reinterpret_cast<double *> (prob->usefulRowInt_); //new double[nrows]; |
| 92 | |
| 93 | # if PRESOLVE_DEBUG |
| 94 | std::cout << "Entering remove_dual_action::presolve, " << nrows << " X " << ncols << "." << std::endl ; |
| 95 | presolve_check_sol(prob) ; |
| 96 | presolve_check_nbasic(prob) ; |
| 97 | # endif |
| 98 | |
| 99 | // This combines the initialization of rdmin/rdmax to extreme values |
| 100 | // (PRESOLVE_INF/-PRESOLVE_INF) with a version of the next loop specialized |
| 101 | // for row slacks. |
| 102 | // In this case, it is always the case that dprice==0.0 and coeff==1.0. |
| 103 | int i; |
| 104 | for ( i = 0; i < nrows; i++) { |
| 105 | double sup = -rlo[i]; // slack ub; corresponds to cup[j] |
| 106 | double slo = -rup[i]; // slack lb; corresponds to clo[j] |
| 107 | bool no_lb = (slo <= -ekkinf); |
| 108 | bool no_ub = (sup >= ekkinf); |
| 109 | |
| 110 | // here, dj==-row dual |
| 111 | // the row slack has no lower bound, but it does have an upper bound, |
| 112 | // then the reduced cost must be <= 0, so the row dual must be >= 0 |
| 113 | rdmin[i] = (no_lb && !no_ub) ? 0.0 : -PRESOLVE_INF; |
| 114 | |
| 115 | rdmax[i] = (no_ub && !no_lb) ? 0.0 : PRESOLVE_INF; |
| 116 | } |
| 117 | |
| 118 | // Look for col singletons and update bounds on dual costs |
| 119 | // Take the min of the maxes and max of the mins |
| 120 | int j; |
| 121 | for ( j = 0; j<ncols; j++) { |
| 122 | if (integerType[j]) |
| 123 | continue; // even if it has infinite bound now .... |
| 124 | bool no_ub = (cup[j] >= ekkinf); |
| 125 | bool no_lb = (clo[j] <= -ekkinf); |
| 126 | |
| 127 | if (hincol[j] == 1 && |
| 128 | |
| 129 | // we need singleton cols that have exactly one bound |
| 130 | (no_ub ^ no_lb)) { |
| 131 | int row = hrow[mcstrt[j]]; |
| 132 | double coeff = colels[mcstrt[j]]; |
| 133 | |
| 134 | PRESOLVEASSERT(fabs(coeff) > ZTOLDP); |
| 135 | |
| 136 | // I don't think the sign of dcost[j] matters |
| 137 | |
| 138 | // this row dual would make this col's reduced cost be 0 |
| 139 | double dprice = maxmin * dcost[j] / coeff; |
| 140 | |
| 141 | // no_ub == !no_lb |
| 142 | // no_ub ==> !(dj<0) |
| 143 | // no_lb ==> !(dj>0) |
| 144 | // I don't think the case where !no_ub has actually been tested |
| 145 | if ((coeff > 0.0) == no_ub) { |
| 146 | // coeff>0 ==> making the row dual larger would make dj *negative* |
| 147 | // ==> dprice is an upper bound on dj if no *ub* |
| 148 | // coeff<0 ==> making the row dual larger would make dj *positive* |
| 149 | // ==> dprice is an upper bound on dj if no *lb* |
| 150 | if (rdmax[row] > dprice) // reduced cost may be positive |
| 151 | rdmax[row] = dprice; |
| 152 | } else if ((coeff < 0.0) == no_lb) { // no lower bound |
| 153 | if (rdmin[row] < dprice) // reduced cost may be negative |
| 154 | rdmin[row] = dprice; |
| 155 | } |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | int *fix_cols = prob->usefulColumnInt_; //new int[ncols]; |
| 160 | |
| 161 | //int *fixdown_cols = new int[ncols]; |
| 162 | |
| 163 | #if PRESOLVE_TIGHTEN_DUALS |
| 164 | double *djmin = new double[ncols]; |
| 165 | double *djmax = new double[ncols]; |
| 166 | #endif |
| 167 | int nfixup_cols = 0; |
| 168 | int nfixdown_cols = ncols; |
| 169 | |
| 170 | int nPass=100; |
| 171 | while (nPass-- > 0) { |
| 172 | int tightened = 0; |
| 173 | /* Perform duality tests */ |
| 174 | for (int j = 0; j<ncols; j++) { |
| 175 | if (hincol[j] > 0) { |
| 176 | CoinBigIndex kcs = mcstrt[j]; |
| 177 | CoinBigIndex kce = kcs + hincol[j]; |
| 178 | // Number of infinite rows |
| 179 | int nflagu = 0; |
| 180 | int nflagl = 0; |
| 181 | // Number of ordinary rows |
| 182 | int nordu = 0; |
| 183 | int nordl = 0; |
| 184 | double ddjlo = maxmin * dcost[j]; |
| 185 | double ddjhi = ddjlo; |
| 186 | |
| 187 | for (CoinBigIndex k = kcs; k < kce; k++) { |
| 188 | int i = hrow[k]; |
| 189 | double coeff = colels[k]; |
| 190 | |
| 191 | if (coeff > 0.0) { |
| 192 | if (rdmin[i] >= -ekkinf2) { |
| 193 | ddjhi -= coeff * rdmin[i]; |
| 194 | nordu ++; |
| 195 | } else { |
| 196 | nflagu ++; |
| 197 | } |
| 198 | if (rdmax[i] <= ekkinf2) { |
| 199 | ddjlo -= coeff * rdmax[i]; |
| 200 | nordl ++; |
| 201 | } else { |
| 202 | nflagl ++; |
| 203 | } |
| 204 | } else { |
| 205 | if (rdmax[i] <= ekkinf2) { |
| 206 | ddjhi -= coeff * rdmax[i]; |
| 207 | nordu ++; |
| 208 | } else { |
| 209 | nflagu ++; |
| 210 | } |
| 211 | if (rdmin[i] >= -ekkinf2) { |
| 212 | ddjlo -= coeff * rdmin[i]; |
| 213 | nordl ++; |
| 214 | } else { |
| 215 | nflagl ++; |
| 216 | } |
| 217 | } |
| 218 | } |
| 219 | // See if we may be able to tighten a dual |
| 220 | if (!integerType[j]) { |
| 221 | if (cup[j]>ekkinf) { |
| 222 | // dj can not be negative |
| 223 | if (nflagu==1&&ddjhi<-ztoldj) { |
| 224 | // We can make bound finite one way |
| 225 | for (CoinBigIndex k = kcs; k < kce; k++) { |
| 226 | int i = hrow[k]; |
| 227 | double coeff = colels[k]; |
| 228 | |
| 229 | if (coeff > 0.0&&rdmin[i] < -ekkinf2) { |
| 230 | // rdmax[i] has upper bound |
| 231 | if (ddjhi<rdmax[i]*coeff-ztoldj) { |
| 232 | double newValue = ddjhi/coeff; |
| 233 | // re-compute lo |
| 234 | if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) { |
| 235 | nflagl--; |
| 236 | ddjlo -= coeff * newValue; |
| 237 | } else if (rdmax[i] <= ekkinf2) { |
| 238 | ddjlo -= coeff * (newValue-rdmax[i]); |
| 239 | } |
| 240 | rdmax[i] = newValue; |
| 241 | tightened++; |
| 242 | #if PRESOLVE_DEBUG |
| 243 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
| 244 | #endif |
| 245 | } |
| 246 | } else if (coeff < 0.0 && rdmax[i] > ekkinf2) { |
| 247 | // rdmin[i] has lower bound |
| 248 | if (ddjhi<rdmin[i]*coeff-ztoldj) { |
| 249 | double newValue = ddjhi/coeff; |
| 250 | // re-compute lo |
| 251 | if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) { |
| 252 | nflagl--; |
| 253 | ddjlo -= coeff * newValue; |
| 254 | } else if (rdmax[i] >= -ekkinf2) { |
| 255 | ddjlo -= coeff * (newValue-rdmin[i]); |
| 256 | } |
| 257 | rdmin[i] = newValue; |
| 258 | tightened++; |
| 259 | #if PRESOLVE_DEBUG |
| 260 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
| 261 | #endif |
| 262 | ddjlo = 0.0; |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | } else if (nflagl==0&&nordl==1&&ddjlo<-ztoldj) { |
| 267 | // We may be able to tighten |
| 268 | for (CoinBigIndex k = kcs; k < kce; k++) { |
| 269 | int i = hrow[k]; |
| 270 | double coeff = colels[k]; |
| 271 | |
| 272 | if (coeff > 0.0) { |
| 273 | rdmax[i] += ddjlo/coeff; |
| 274 | ddjlo =0.0; |
| 275 | tightened++; |
| 276 | #if PRESOLVE_DEBUG |
| 277 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
| 278 | #endif |
| 279 | } else if (coeff < 0.0 ) { |
| 280 | rdmin[i] += ddjlo/coeff; |
| 281 | ddjlo =0.0; |
| 282 | tightened++; |
| 283 | #if PRESOLVE_DEBUG |
| 284 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
| 285 | #endif |
| 286 | } |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | #if 0 |
| 291 | if (clo[j]<-ekkinf) { |
| 292 | // dj can not be positive |
| 293 | if (ddjlo>ztoldj&&nflagl==1) { |
| 294 | // We can make bound finite one way |
| 295 | for (CoinBigIndex k = kcs; k < kce; k++) { |
| 296 | int i = hrow[k]; |
| 297 | double coeff = colels[k]; |
| 298 | |
| 299 | if (coeff < 0.0&&rdmin[i] < -ekkinf2) { |
| 300 | // rdmax[i] has upper bound |
| 301 | if (ddjlo>rdmax[i]*coeff+ztoldj) { |
| 302 | double newValue = ddjlo/coeff; |
| 303 | // re-compute hi |
| 304 | if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) { |
| 305 | nflagu--; |
| 306 | ddjhi -= coeff * newValue; |
| 307 | } else if (rdmax[i] <= ekkinf2) { |
| 308 | ddjhi -= coeff * (newValue-rdmax[i]); |
| 309 | } |
| 310 | rdmax[i] = newValue; |
| 311 | tightened++; |
| 312 | #if PRESOLVE_DEBUG |
| 313 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
| 314 | #endif |
| 315 | } |
| 316 | } else if (coeff > 0.0 && rdmax[i] > ekkinf2) { |
| 317 | // rdmin[i] has lower bound |
| 318 | if (ddjlo>rdmin[i]*coeff+ztoldj) { |
| 319 | double newValue = ddjlo/coeff; |
| 320 | // re-compute lo |
| 321 | if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) { |
| 322 | nflagu--; |
| 323 | ddjhi -= coeff * newValue; |
| 324 | } else if (rdmax[i] >= -ekkinf2) { |
| 325 | ddjhi -= coeff * (newValue-rdmin[i]); |
| 326 | } |
| 327 | rdmin[i] = newValue; |
| 328 | tightened++; |
| 329 | #if PRESOLVE_DEBUG |
| 330 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
| 331 | #endif |
| 332 | } |
| 333 | } |
| 334 | } |
| 335 | } else if (nflagu==0&&nordu==1&&ddjhi>ztoldj) { |
| 336 | // We may be able to tighten |
| 337 | for (CoinBigIndex k = kcs; k < kce; k++) { |
| 338 | int i = hrow[k]; |
| 339 | double coeff = colels[k]; |
| 340 | |
| 341 | if (coeff < 0.0) { |
| 342 | rdmax[i] += ddjhi/coeff; |
| 343 | ddjhi =0.0; |
| 344 | tightened++; |
| 345 | #if PRESOLVE_DEBUG |
| 346 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
| 347 | #endif |
| 348 | } else if (coeff > 0.0 ) { |
| 349 | rdmin[i] += ddjhi/coeff; |
| 350 | ddjhi =0.0; |
| 351 | tightened++; |
| 352 | #if PRESOLVE_DEBUG |
| 353 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
| 354 | #endif |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | } |
| 359 | #endif |
| 360 | } |
| 361 | |
| 362 | #if PRESOLVE_TIGHTEN_DUALS |
| 363 | djmin[j] = (nflagl ? -PRESOLVE_INF : ddjlo); |
| 364 | djmax[j] = (nflagu ? PRESOLVE_INF : ddjhi); |
| 365 | #endif |
| 366 | |
| 367 | if (ddjlo > ztoldj && nflagl == 0&&!prob->colProhibited2(j)) { |
| 368 | // dj>0 at optimality ==> must be at lower bound |
| 369 | if (clo[j] <= -ekkinf) { |
| 370 | prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDB, |
| 371 | prob->messages()) |
| 372 | <<j |
| 373 | <<CoinMessageEol; |
| 374 | prob->status_ |= 2; |
| 375 | break; |
| 376 | } else { |
| 377 | fix_cols[--nfixdown_cols] = j; |
| 378 | PRESOLVE_DETAIL_PRINT(printf("pre_duallo %dC E\n" ,j)); |
| 379 | # if PRESOLVE_DEBUG |
| 380 | printf("NDUAL: fixing x<%d>" ,fix_cols[nfixdown_cols]) ; |
| 381 | if (csol) printf(" = %g" ,csol[j]) ; |
| 382 | printf(" at lb = %g.\n" ,clo[j]) ; |
| 383 | # endif |
| 384 | //if (csol[j]-clo[j]>1.0e-7) |
| 385 | //printf("down %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]); |
| 386 | // User may have given us feasible solution - move if simple |
| 387 | if (csol) { |
| 388 | # if 0 |
| 389 | /* |
| 390 | Except it's not simple. The net result is that we end up with an |
| 391 | excess of basic variables. |
| 392 | */ |
| 393 | if (csol[j]-clo[j]>1.0e-7&&hincol[j]==1) { |
| 394 | double value_j = colels[mcstrt[j]]; |
| 395 | double distance_j = csol[j]-clo[j]; |
| 396 | int row=hrow[mcstrt[j]]; |
| 397 | // See if another column can take value |
| 398 | for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) { |
| 399 | int k = hcol[kk]; |
| 400 | if (colstat[k] == CoinPrePostsolveMatrix::superBasic) |
| 401 | continue ; |
| 402 | |
| 403 | if (hincol[k]==1&&k!=j) { |
| 404 | double value_k = rowels[kk]; |
| 405 | double movement; |
| 406 | if (value_k*value_j>0.0) { |
| 407 | // k needs to increase |
| 408 | double distance_k = cup[k]-csol[k]; |
| 409 | movement = CoinMin((distance_j*value_j)/value_k,distance_k); |
| 410 | } else { |
| 411 | // k needs to decrease |
| 412 | double distance_k = clo[k]-csol[k]; |
| 413 | movement = CoinMax((distance_j*value_j)/value_k,distance_k); |
| 414 | } |
| 415 | if (relEq(movement,0)) continue ; |
| 416 | |
| 417 | csol[k] += movement; |
| 418 | if (relEq(csol[k],clo[k])) |
| 419 | { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; } |
| 420 | else |
| 421 | if (relEq(csol[k],cup[k])) |
| 422 | { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; } |
| 423 | else |
| 424 | if (colstat[k] != CoinPrePostsolveMatrix::isFree) |
| 425 | { colstat[k] = CoinPrePostsolveMatrix::basic ; } |
| 426 | printf("NDUAL: x<%d> moved %g to %g; " , |
| 427 | k,movement,csol[k]) ; |
| 428 | printf("lb = %g, ub = %g, status now %s.\n" , |
| 429 | clo[k],cup[k],columnStatusString(colstat[k])) ; |
| 430 | distance_j -= (movement*value_k)/value_j; |
| 431 | csol[j] -= (movement*value_k)/value_j; |
| 432 | if (distance_j<1.0e-7) |
| 433 | break; |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | # endif // repair solution. |
| 438 | |
| 439 | csol[j] = clo[j] ; // but the bottom line is we've changed x<j> |
| 440 | colstat[j] = CoinPrePostsolveMatrix::atLowerBound ; |
| 441 | } |
| 442 | } |
| 443 | } else if (ddjhi < -ztoldj && nflagu == 0&&!prob->colProhibited2(j)) { |
| 444 | // dj<0 at optimality ==> must be at upper bound |
| 445 | if (cup[j] >= ekkinf) { |
| 446 | prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDA, |
| 447 | prob->messages()) |
| 448 | <<j |
| 449 | <<CoinMessageEol; |
| 450 | prob->status_ |= 2; |
| 451 | break; |
| 452 | } else { |
| 453 | PRESOLVE_DETAIL_PRINT(printf("pre_dualup %dC E\n" ,j)); |
| 454 | fix_cols[nfixup_cols++] = j; |
| 455 | # if PRESOLVE_DEBUG |
| 456 | printf("NDUAL: fixing x<%d>" ,fix_cols[nfixup_cols-1]) ; |
| 457 | if (csol) printf(" = %g" ,csol[j]) ; |
| 458 | printf(" at ub = %g.\n" ,cup[j]) ; |
| 459 | # endif |
| 460 | // User may have given us feasible solution - move if simple |
| 461 | // See comments for `fix at lb' case above. |
| 462 | //if (cup[j]-csol[j]>1.0e-7) |
| 463 | //printf("up %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]); |
| 464 | if (csol) { |
| 465 | # if 0 |
| 466 | // See comments above. |
| 467 | if (cup[j]-csol[j]>1.0e-7&&hincol[j]==1) { |
| 468 | double value_j = colels[mcstrt[j]]; |
| 469 | double distance_j = csol[j]-cup[j]; |
| 470 | int row=hrow[mcstrt[j]]; |
| 471 | // See if another column can take value |
| 472 | for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) { |
| 473 | int k = hcol[kk]; |
| 474 | if (colstat[k] == CoinPrePostsolveMatrix::superBasic) |
| 475 | continue ; |
| 476 | |
| 477 | if (hincol[k]==1&&k!=j) { |
| 478 | double value_k = rowels[kk]; |
| 479 | double movement; |
| 480 | if (value_k*value_j<0.0) { |
| 481 | // k needs to increase |
| 482 | double distance_k = cup[k]-csol[k]; |
| 483 | movement = CoinMin((distance_j*value_j)/value_k,distance_k); |
| 484 | } else { |
| 485 | // k needs to decrease |
| 486 | double distance_k = clo[k]-csol[k]; |
| 487 | movement = CoinMax((distance_j*value_j)/value_k,distance_k); |
| 488 | } |
| 489 | if (relEq(movement,0)) continue ; |
| 490 | |
| 491 | csol[k] += movement; |
| 492 | if (relEq(csol[k],clo[k])) |
| 493 | { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; } |
| 494 | else |
| 495 | if (relEq(csol[k],cup[k])) |
| 496 | { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; } |
| 497 | else |
| 498 | if (colstat[k] != CoinPrePostsolveMatrix::isFree) |
| 499 | { colstat[k] = CoinPrePostsolveMatrix::basic ; } |
| 500 | printf("NDUAL: x<%d> moved %g to %g; " , |
| 501 | k,movement,csol[k]) ; |
| 502 | printf("lb = %g, ub = %g, status now %s.\n" , |
| 503 | clo[k],cup[k],columnStatusString(colstat[k])) ; |
| 504 | distance_j -= (movement*value_k)/value_j; |
| 505 | csol[j] -= (movement*value_k)/value_j; |
| 506 | if (distance_j>-1.0e-7) |
| 507 | break; |
| 508 | } |
| 509 | } |
| 510 | } |
| 511 | # endif |
| 512 | csol[j] = cup[j] ; // but the bottom line is we've changed x<j> |
| 513 | colstat[j] = CoinPrePostsolveMatrix::atUpperBound ; |
| 514 | } |
| 515 | } |
| 516 | } |
| 517 | } |
| 518 | } |
| 519 | |
| 520 | // I don't know why I stopped doing this. |
| 521 | #if PRESOLVE_TIGHTEN_DUALS |
| 522 | const double *rowels = prob->rowels_; |
| 523 | const int *hcol = prob->hcol_; |
| 524 | const CoinBigIndex *mrstrt = prob->mrstrt_; |
| 525 | int *hinrow = prob->hinrow_; |
| 526 | // tighten row dual bounds, as described on p. 229 |
| 527 | for (int i = 0; i < nrows; i++) { |
| 528 | bool no_ub = (rup[i] >= ekkinf); |
| 529 | bool no_lb = (rlo[i] <= -ekkinf); |
| 530 | |
| 531 | if ((no_ub ^ no_lb) == true) { |
| 532 | CoinBigIndex krs = mrstrt[i]; |
| 533 | CoinBigIndex kre = krs + hinrow[i]; |
| 534 | double rmax = rdmax[i]; |
| 535 | double rmin = rdmin[i]; |
| 536 | |
| 537 | // all row columns are non-empty |
| 538 | for (CoinBigIndex k=krs; k<kre; k++) { |
| 539 | double coeff = rowels[k]; |
| 540 | int icol = hcol[k]; |
| 541 | double djmax0 = djmax[icol]; |
| 542 | double djmin0 = djmin[icol]; |
| 543 | |
| 544 | if (no_ub) { |
| 545 | // dj must not be negative |
| 546 | if (coeff > ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol]>=ekkinf) { |
| 547 | double bnd = djmax0 / coeff; |
| 548 | if (rmax > bnd) { |
| 549 | #if PRESOLVE_DEBUG |
| 550 | printf("MAX TIGHT[%d,%d]: %g --> %g\n" , i,hrow[k], rdmax[i], bnd); |
| 551 | #endif |
| 552 | rdmax[i] = rmax = bnd; |
| 553 | tightened ++; |
| 554 | } |
| 555 | } else if (coeff < -ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol] >= ekkinf) { |
| 556 | double bnd = djmax0 / coeff ; |
| 557 | if (rmin < bnd) { |
| 558 | #if PRESOLVE_DEBUG |
| 559 | printf("MIN TIGHT[%d,%d]: %g --> %g\n" , i, hrow[k], rdmin[i], bnd); |
| 560 | #endif |
| 561 | rdmin[i] = rmin = bnd; |
| 562 | tightened ++; |
| 563 | } |
| 564 | } |
| 565 | } else { // no_lb |
| 566 | // dj must not be positive |
| 567 | if (coeff > ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol]<=-ekkinf) { |
| 568 | double bnd = djmin0 / coeff ; |
| 569 | if (rmin < bnd) { |
| 570 | #if PRESOLVE_DEBUG |
| 571 | printf("MIN1 TIGHT[%d,%d]: %g --> %g\n" , i, hrow[k], rdmin[i], bnd); |
| 572 | #endif |
| 573 | rdmin[i] = rmin = bnd; |
| 574 | tightened ++; |
| 575 | } |
| 576 | } else if (coeff < -ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) { |
| 577 | double bnd = djmin0 / coeff ; |
| 578 | if (rmax > bnd) { |
| 579 | #if PRESOLVE_DEBUG |
| 580 | printf("MAX TIGHT1[%d,%d]: %g --> %g\n" , i,hrow[k], rdmax[i], bnd); |
| 581 | #endif |
| 582 | rdmax[i] = rmax = bnd; |
| 583 | tightened ++; |
| 584 | } |
| 585 | } |
| 586 | } |
| 587 | } |
| 588 | } |
| 589 | } |
| 590 | #endif |
| 591 | |
| 592 | if (tightened<100||nfixdown_cols<ncols||nfixup_cols) |
| 593 | break; |
| 594 | #if PRESOLVE_TIGHTEN_DUALS |
| 595 | else |
| 596 | printf("DUAL TIGHTENED! %d\n" , tightened); |
| 597 | #endif |
| 598 | } |
| 599 | assert (nfixup_cols<=nfixdown_cols); |
| 600 | if (nfixup_cols) { |
| 601 | #if PRESOLVE_DEBUG |
| 602 | printf("NDUAL: %d up" , nfixup_cols); |
| 603 | for (i = 0 ; i < nfixup_cols ; i++) printf(" %d" ,fix_cols[i]) ; |
| 604 | printf(".\n" ) ; |
| 605 | #endif |
| 606 | next = make_fixed_action::presolve(prob, fix_cols, nfixup_cols, false, next); |
| 607 | } |
| 608 | |
| 609 | if (nfixdown_cols<ncols) { |
| 610 | int * fixdown_cols = fix_cols+nfixdown_cols; |
| 611 | nfixdown_cols = ncols-nfixdown_cols; |
| 612 | #if PRESOLVE_DEBUG |
| 613 | printf("NDUAL: %d down" , nfixdown_cols); |
| 614 | for (i = 0 ; i < nfixdown_cols ; i++) printf(" %d" ,fixdown_cols[i]) ; |
| 615 | printf(".\n" ) ; |
| 616 | #endif |
| 617 | next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols, true, next); |
| 618 | } |
| 619 | // If dual says so then we can make equality row |
| 620 | // Also if cost is in right direction and only one binding row for variable |
| 621 | // We may wish to think about giving preference to rows with 2 or 3 elements |
| 622 | /* |
| 623 | Gack! Ok, I can appreciate the thought here, but I'm seriously skeptical |
| 624 | about writing canFix[0] before reading rdmin[0]. After that, we should be out |
| 625 | of the interference zone for the typical situation where sizeof(double) is |
| 626 | twice sizeof(int). |
| 627 | */ |
| 628 | int * canFix = reinterpret_cast<int *> (rdmin); |
| 629 | for ( i = 0; i < nrows; i++) { |
| 630 | bool no_lb = (rlo[i] <= -ekkinf); |
| 631 | bool no_ub = (rup[i] >= ekkinf); |
| 632 | canFix[i]=0; |
| 633 | if (no_ub && !no_lb ) { |
| 634 | if ( rdmin[i]>0.0) |
| 635 | canFix[i]=-1; |
| 636 | else |
| 637 | canFix[i]=-2; |
| 638 | } else if (no_lb && !no_ub ) { |
| 639 | if (rdmax[i]<0.0) |
| 640 | canFix[i]=1; |
| 641 | else |
| 642 | canFix[i]=2; |
| 643 | } |
| 644 | } |
| 645 | for (j = 0; j<ncols; j++) { |
| 646 | if (hincol[j]<=1) |
| 647 | continue; |
| 648 | if (integerType[j]) |
| 649 | continue; // even if it has infinite bound now .... |
| 650 | CoinBigIndex kcs = mcstrt[j]; |
| 651 | CoinBigIndex kce = kcs + hincol[j]; |
| 652 | int bindingUp=-1; |
| 653 | int bindingDown=-1; |
| 654 | if (cup[j]<ekkinf) |
| 655 | bindingUp=-2; |
| 656 | if (clo[j]>-ekkinf) |
| 657 | bindingDown=-2; |
| 658 | for (CoinBigIndex k = kcs; k < kce; k++) { |
| 659 | int i = hrow[k]; |
| 660 | if (abs(canFix[i])!=2) { |
| 661 | bindingUp=-2; |
| 662 | bindingDown=-2; |
| 663 | break; |
| 664 | } |
| 665 | double coeff = colels[k]; |
| 666 | if (coeff>0.0) { |
| 667 | if (canFix[i]==2) { |
| 668 | // binding up |
| 669 | if (bindingUp==-1) |
| 670 | bindingUp = i; |
| 671 | else |
| 672 | bindingUp = -2; |
| 673 | } else { |
| 674 | // binding down |
| 675 | if (bindingDown==-1) |
| 676 | bindingDown = i; |
| 677 | else |
| 678 | bindingDown = -2; |
| 679 | } |
| 680 | } else { |
| 681 | if (canFix[i]==2) { |
| 682 | // binding down |
| 683 | if (bindingDown==-1) |
| 684 | bindingDown = i; |
| 685 | else |
| 686 | bindingDown = -2; |
| 687 | } else { |
| 688 | // binding up |
| 689 | if (bindingUp==-1) |
| 690 | bindingUp = i; |
| 691 | else |
| 692 | bindingUp = -2; |
| 693 | } |
| 694 | } |
| 695 | } |
| 696 | double cost = maxmin * dcost[j]; |
| 697 | if (bindingUp>-2&&cost<=0.0) { |
| 698 | // might as well make equality |
| 699 | if (bindingUp>=0) { |
| 700 | canFix[bindingUp] /= 2; //So -2 goes to -1 etc |
| 701 | //printf("fixing row %d to ub by %d\n",bindingUp,j); |
| 702 | } else { |
| 703 | //printf("binding up row by %d\n",j); |
| 704 | } |
| 705 | } else if (bindingDown>-2 &&cost>=0.0) { |
| 706 | // might as well make equality |
| 707 | if (bindingDown>=0) { |
| 708 | canFix[bindingDown] /= 2; //So -2 goes to -1 etc |
| 709 | //printf("fixing row %d to lb by %d\n",bindingDown,j); |
| 710 | } else { |
| 711 | //printf("binding down row by %d\n",j); |
| 712 | } |
| 713 | } |
| 714 | } |
| 715 | // can't fix if integer and non-unit coefficient |
| 716 | //const double *rowels = prob->rowels_; |
| 717 | //const int *hcol = prob->hcol_; |
| 718 | //const CoinBigIndex *mrstrt = prob->mrstrt_; |
| 719 | //int *hinrow = prob->hinrow_; |
| 720 | for ( i = 0; i < nrows; i++) { |
| 721 | if (abs(canFix[i])==1) { |
| 722 | CoinBigIndex krs = mrstrt[i]; |
| 723 | CoinBigIndex kre = krs + hinrow[i]; |
| 724 | for (CoinBigIndex k=krs; k<kre; k++) { |
| 725 | int icol = hcol[k]; |
| 726 | if (cup[icol]>clo[icol]&&integerType[icol]) { |
| 727 | canFix[i]=0; // not safe |
| 728 | #ifdef COIN_DEVELOP |
| 729 | printf("no dual something CoinPresolveDual row %d col %d\n" , |
| 730 | i,icol); |
| 731 | #endif |
| 732 | } |
| 733 | } |
| 734 | } |
| 735 | if (canFix[i]==1) { |
| 736 | rlo[i]=rup[i]; |
| 737 | prob->addRow(i); |
| 738 | } else if (canFix[i]==-1) { |
| 739 | rup[i]=rlo[i]; |
| 740 | prob->addRow(i); |
| 741 | } |
| 742 | } |
| 743 | |
| 744 | //delete[]rdmin; |
| 745 | //delete[]rdmax; |
| 746 | |
| 747 | //delete[]fixup_cols; |
| 748 | //delete[]fixdown_cols; |
| 749 | |
| 750 | #if PRESOLVE_TIGHTEN_DUALS |
| 751 | delete[]djmin; |
| 752 | delete[]djmax; |
| 753 | #endif |
| 754 | |
| 755 | if (prob->tuning_) { |
| 756 | double thisTime=CoinCpuTime(); |
| 757 | int droppedRows = prob->countEmptyRows() - startEmptyRows; |
| 758 | int droppedColumns = prob->countEmptyCols() - startEmptyColumns; |
| 759 | printf("CoinPresolveDual(1) - %d rows, %d columns dropped in time %g, total %g\n" , |
| 760 | droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); |
| 761 | } |
| 762 | |
| 763 | # if PRESOLVE_DEBUG |
| 764 | presolve_check_sol(prob) ; |
| 765 | presolve_check_nbasic(prob) ; |
| 766 | std::cout << "Leaving remove_dual_action::presolve." << std::endl ; |
| 767 | # endif |
| 768 | |
| 769 | return (next); |
| 770 | } |
| 771 | |