/* This routine looks to be something of a work in progres. See the comment that begins with `Gack!'. And down in the bound propagation loop, why do we only work with variables with u_j = infty? The corresponding section of code for l_j = -infty is ifdef'd away. And why exclude the code protected by PRESOLVE_TIGHTEN_DUALS? And why are we using ekkinf instead of PRESOLVE_INF? There is no postsolve action because once we've identified a variable to fix we can invoke make_fixed_action. */ const CoinPresolveAction *remove_dual_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double startTime = 0.0; int startEmptyRows=0; int startEmptyColumns = 0; if (prob->tuning_) { startTime = CoinCpuTime(); startEmptyRows = prob->countEmptyRows(); startEmptyColumns = prob->countEmptyCols(); } double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int ncols = prob->ncols_; double *clo = prob->clo_; double *cup = prob->cup_; unsigned char *colstat = prob->colstat_ ; // Used only in `fix if simple' section below. Remove dec'l to avoid // GCC compile warning. // double *rowels = prob->rowels_; int *hcol = prob->hcol_; CoinBigIndex *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; double *csol = prob->sol_; int nrows = prob->nrows_; double *rlo = prob->rlo_; double *rup = prob->rup_; double *dcost = prob->cost_; const unsigned char *integerType = prob->integerType_; const double maxmin = prob->maxmin_; const double ekkinf = 1e28; const double ekkinf2 = 1e20; const double ztoldj = prob->ztoldj_; CoinRelFltEq relEq(prob->ztolzb_) ; double *rdmin = prob->usefulRowDouble_; //new double[nrows]; double *rdmax = reinterpret_cast<double *> (prob->usefulRowInt_); //new double[nrows]; # if PRESOLVE_DEBUG std::cout << "Entering remove_dual_action::presolve, " << nrows << " X " << ncols << "." << std::endl ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif // This combines the initialization of rdmin/rdmax to extreme values // (PRESOLVE_INF/-PRESOLVE_INF) with a version of the next loop specialized // for row slacks. // In this case, it is always the case that dprice==0.0 and coeff==1.0. int i; for ( i = 0; i < nrows; i++) { double sup = -rlo[i]; // slack ub; corresponds to cup[j] double slo = -rup[i]; // slack lb; corresponds to clo[j] bool no_lb = (slo <= -ekkinf); bool no_ub = (sup >= ekkinf); // here, dj==-row dual // the row slack has no lower bound, but it does have an upper bound, // then the reduced cost must be <= 0, so the row dual must be >= 0 rdmin[i] = (no_lb && !no_ub) ? 0.0 : -PRESOLVE_INF; rdmax[i] = (no_ub && !no_lb) ? 0.0 : PRESOLVE_INF; } // Look for col singletons and update bounds on dual costs // Take the min of the maxes and max of the mins int j; for ( j = 0; j<ncols; j++) { if (integerType[j]) continue; // even if it has infinite bound now .... bool no_ub = (cup[j] >= ekkinf); bool no_lb = (clo[j] <= -ekkinf); if (hincol[j] == 1 && // we need singleton cols that have exactly one bound (no_ub ^ no_lb)) { int row = hrow[mcstrt[j]]; double coeff = colels[mcstrt[j]]; PRESOLVEASSERT(fabs(coeff) > ZTOLDP); // I don't think the sign of dcost[j] matters // this row dual would make this col's reduced cost be 0 double dprice = maxmin * dcost[j] / coeff; // no_ub == !no_lb // no_ub ==> !(dj<0) // no_lb ==> !(dj>0) // I don't think the case where !no_ub has actually been tested if ((coeff > 0.0) == no_ub) { // coeff>0 ==> making the row dual larger would make dj *negative* // ==> dprice is an upper bound on dj if no *ub* // coeff<0 ==> making the row dual larger would make dj *positive* // ==> dprice is an upper bound on dj if no *lb* if (rdmax[row] > dprice) // reduced cost may be positive rdmax[row] = dprice; } else if ((coeff < 0.0) == no_lb) { // no lower bound if (rdmin[row] < dprice) // reduced cost may be negative rdmin[row] = dprice; } } } int *fix_cols = prob->usefulColumnInt_; //new int[ncols]; //int *fixdown_cols = new int[ncols]; #if PRESOLVE_TIGHTEN_DUALS double *djmin = new double[ncols]; double *djmax = new double[ncols]; #endif int nfixup_cols = 0; int nfixdown_cols = ncols; int nPass=100; while (nPass-->0) { int tightened = 0; /* Perform duality tests */ for (int j = 0; j<ncols; j++) { if (hincol[j] > 0) { CoinBigIndex kcs = mcstrt[j]; CoinBigIndex kce = kcs + hincol[j]; // Number of infinite rows int nflagu = 0; int nflagl = 0; // Number of ordinary rows int nordu = 0; int nordl = 0; double ddjlo = maxmin * dcost[j]; double ddjhi = ddjlo; for (CoinBigIndex k = kcs; k < kce; k++) { int i = hrow[k]; double coeff = colels[k]; if (coeff > 0.0) { if (rdmin[i] >= -ekkinf2) { ddjhi -= coeff * rdmin[i]; nordu ++; } else { nflagu ++; } if (rdmax[i] <= ekkinf2) { ddjlo -= coeff * rdmax[i]; nordl ++; } else { nflagl ++; } } else { if (rdmax[i] <= ekkinf2) { ddjhi -= coeff * rdmax[i]; nordu ++; } else { nflagu ++; } if (rdmin[i] >= -ekkinf2) { ddjlo -= coeff * rdmin[i]; nordl ++; } else { nflagl ++; } } } // See if we may be able to tighten a dual if (!integerType[j]) { if (cup[j]>ekkinf) { // dj can not be negative if (nflagu==1&&ddjhi<-ztoldj) { // We can make bound finite one way for (CoinBigIndex k = kcs; k < kce; k++) { int i = hrow[k]; double coeff = colels[k]; if (coeff > 0.0&&rdmin[i] < -ekkinf2) { // rdmax[i] has upper bound if (ddjhi<rdmax[i]*coeff-ztoldj) { double newValue = ddjhi/coeff; // re-compute lo if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) { nflagl--; ddjlo -= coeff * newValue; } else if (rdmax[i] <= ekkinf2) { ddjlo -= coeff * (newValue-rdmax[i]); } rdmax[i] = newValue; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]); #endif } } else if (coeff < 0.0 && rdmax[i] > ekkinf2) { // rdmin[i] has lower bound if (ddjhi<rdmin[i]*coeff-ztoldj) { double newValue = ddjhi/coeff; // re-compute lo if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) { nflagl--; ddjlo -= coeff * newValue; } else if (rdmax[i] >= -ekkinf2) { ddjlo -= coeff * (newValue-rdmin[i]); } rdmin[i] = newValue; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]); #endif ddjlo = 0.0; } } } } else if (nflagl==0&&nordl==1&&ddjlo<-ztoldj) { // We may be able to tighten for (CoinBigIndex k = kcs; k < kce; k++) { int i = hrow[k]; double coeff = colels[k]; if (coeff > 0.0) { rdmax[i] += ddjlo/coeff; ddjlo =0.0; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]); #endif } else if (coeff < 0.0 ) { rdmin[i] += ddjlo/coeff; ddjlo =0.0; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]); #endif } } } } #if 0 if (clo[j]<-ekkinf) { // dj can not be positive if (ddjlo>ztoldj&&nflagl==1) { // We can make bound finite one way for (CoinBigIndex k = kcs; k < kce; k++) { int i = hrow[k]; double coeff = colels[k]; if (coeff < 0.0&&rdmin[i] < -ekkinf2) { // rdmax[i] has upper bound if (ddjlo>rdmax[i]*coeff+ztoldj) { double newValue = ddjlo/coeff; // re-compute hi if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) { nflagu--; ddjhi -= coeff * newValue; } else if (rdmax[i] <= ekkinf2) { ddjhi -= coeff * (newValue-rdmax[i]); } rdmax[i] = newValue; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]); #endif } } else if (coeff > 0.0 && rdmax[i] > ekkinf2) { // rdmin[i] has lower bound if (ddjlo>rdmin[i]*coeff+ztoldj) { double newValue = ddjlo/coeff; // re-compute lo if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) { nflagu--; ddjhi -= coeff * newValue; } else if (rdmax[i] >= -ekkinf2) { ddjhi -= coeff * (newValue-rdmin[i]); } rdmin[i] = newValue; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]); #endif } } } } else if (nflagu==0&&nordu==1&&ddjhi>ztoldj) { // We may be able to tighten for (CoinBigIndex k = kcs; k < kce; k++) { int i = hrow[k]; double coeff = colels[k]; if (coeff < 0.0) { rdmax[i] += ddjhi/coeff; ddjhi =0.0; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]); #endif } else if (coeff > 0.0 ) { rdmin[i] += ddjhi/coeff; ddjhi =0.0; tightened++; #if PRESOLVE_DEBUG printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]); #endif } } } } #endif } #if PRESOLVE_TIGHTEN_DUALS djmin[j] = (nflagl ? -PRESOLVE_INF : ddjlo); djmax[j] = (nflagu ? PRESOLVE_INF : ddjhi); #endif if (ddjlo > ztoldj && nflagl == 0&&!prob->colProhibited2(j)) { // dj>0 at optimality ==> must be at lower bound if (clo[j] <= -ekkinf) { prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDB, prob->messages()) <<j <<CoinMessageEol; prob->status_ |= 2; break; } else { fix_cols[--nfixdown_cols] = j; PRESOLVE_DETAIL_PRINT(printf("pre_duallo %dC E\n",j)); # if PRESOLVE_DEBUG printf("NDUAL: fixing x<%d>",fix_cols[nfixdown_cols]) ; if (csol) printf(" = %g",csol[j]) ; printf(" at lb = %g.\n",clo[j]) ; # endif //if (csol[j]-clo[j]>1.0e-7) //printf("down %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]); // User may have given us feasible solution - move if simple if (csol) { # if 0 /* Except it's not simple. The net result is that we end up with an excess of basic variables. */ if (csol[j]-clo[j]>1.0e-7&&hincol[j]==1) { double value_j = colels[mcstrt[j]]; double distance_j = csol[j]-clo[j]; int row=hrow[mcstrt[j]]; // See if another column can take value for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) { int k = hcol[kk]; if (colstat[k] == CoinPrePostsolveMatrix::superBasic) continue ; if (hincol[k]==1&&k!=j) { double value_k = rowels[kk]; double movement; if (value_k*value_j>0.0) { // k needs to increase double distance_k = cup[k]-csol[k]; movement = CoinMin((distance_j*value_j)/value_k,distance_k); } else { // k needs to decrease double distance_k = clo[k]-csol[k]; movement = CoinMax((distance_j*value_j)/value_k,distance_k); } if (relEq(movement,0)) continue ; csol[k] += movement; if (relEq(csol[k],clo[k])) { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; } else if (relEq(csol[k],cup[k])) { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; } else if (colstat[k] != CoinPrePostsolveMatrix::isFree) { colstat[k] = CoinPrePostsolveMatrix::basic ; } printf("NDUAL: x<%d> moved %g to %g; ", k,movement,csol[k]) ; printf("lb = %g, ub = %g, status now %s.\n", clo[k],cup[k],columnStatusString(colstat[k])) ; distance_j -= (movement*value_k)/value_j; csol[j] -= (movement*value_k)/value_j; if (distance_j<1.0e-7) break; } } } # endif // repair solution. csol[j] = clo[j] ; // but the bottom line is we've changed x<j> colstat[j] = CoinPrePostsolveMatrix::atLowerBound ; } } } else if (ddjhi < -ztoldj && nflagu == 0&&!prob->colProhibited2(j)) { // dj<0 at optimality ==> must be at upper bound if (cup[j] >= ekkinf) { prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDA, prob->messages()) <<j <<CoinMessageEol; prob->status_ |= 2; break; } else { PRESOLVE_DETAIL_PRINT(printf("pre_dualup %dC E\n",j)); fix_cols[nfixup_cols++] = j; # if PRESOLVE_DEBUG printf("NDUAL: fixing x<%d>",fix_cols[nfixup_cols-1]) ; if (csol) printf(" = %g",csol[j]) ; printf(" at ub = %g.\n",cup[j]) ; # endif // User may have given us feasible solution - move if simple // See comments for `fix at lb' case above. //if (cup[j]-csol[j]>1.0e-7) //printf("up %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]); if (csol) { # if 0 // See comments above. if (cup[j]-csol[j]>1.0e-7&&hincol[j]==1) { double value_j = colels[mcstrt[j]]; double distance_j = csol[j]-cup[j]; int row=hrow[mcstrt[j]]; // See if another column can take value for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) { int k = hcol[kk]; if (colstat[k] == CoinPrePostsolveMatrix::superBasic) continue ; if (hincol[k]==1&&k!=j) { double value_k = rowels[kk]; double movement; if (value_k*value_j<0.0) { // k needs to increase double distance_k = cup[k]-csol[k]; movement = CoinMin((distance_j*value_j)/value_k,distance_k); } else { // k needs to decrease double distance_k = clo[k]-csol[k]; movement = CoinMax((distance_j*value_j)/value_k,distance_k); } if (relEq(movement,0)) continue ; csol[k] += movement; if (relEq(csol[k],clo[k])) { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; } else if (relEq(csol[k],cup[k])) { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; } else if (colstat[k] != CoinPrePostsolveMatrix::isFree) { colstat[k] = CoinPrePostsolveMatrix::basic ; } printf("NDUAL: x<%d> moved %g to %g; ", k,movement,csol[k]) ; printf("lb = %g, ub = %g, status now %s.\n", clo[k],cup[k],columnStatusString(colstat[k])) ; distance_j -= (movement*value_k)/value_j; csol[j] -= (movement*value_k)/value_j; if (distance_j>-1.0e-7) break; } } } # endif csol[j] = cup[j] ; // but the bottom line is we've changed x<j> colstat[j] = CoinPrePostsolveMatrix::atUpperBound ; } } } } } // I don't know why I stopped doing this. #if PRESOLVE_TIGHTEN_DUALS const double *rowels = prob->rowels_; const int *hcol = prob->hcol_; const CoinBigIndex *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; // tighten row dual bounds, as described on p. 229 for (int i = 0; i < nrows; i++) { bool no_ub = (rup[i] >= ekkinf); bool no_lb = (rlo[i] <= -ekkinf); if ((no_ub ^ no_lb) == true) { CoinBigIndex krs = mrstrt[i]; CoinBigIndex kre = krs + hinrow[i]; double rmax = rdmax[i]; double rmin = rdmin[i]; // all row columns are non-empty for (CoinBigIndex k=krs; k<kre; k++) { double coeff = rowels[k]; int icol = hcol[k]; double djmax0 = djmax[icol]; double djmin0 = djmin[icol]; if (no_ub) { // dj must not be negative if (coeff > ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol]>=ekkinf) { double bnd = djmax0 / coeff; if (rmax > bnd) { #if PRESOLVE_DEBUG printf("MAX TIGHT[%d,%d]: %g --> %g\n", i,hrow[k], rdmax[i], bnd); #endif rdmax[i] = rmax = bnd; tightened ++; } } else if (coeff < -ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol] >= ekkinf) { double bnd = djmax0 / coeff ; if (rmin < bnd) { #if PRESOLVE_DEBUG printf("MIN TIGHT[%d,%d]: %g --> %g\n", i, hrow[k], rdmin[i], bnd); #endif rdmin[i] = rmin = bnd; tightened ++; } } } else { // no_lb // dj must not be positive if (coeff > ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol]<=-ekkinf) { double bnd = djmin0 / coeff ; if (rmin < bnd) { #if PRESOLVE_DEBUG printf("MIN1 TIGHT[%d,%d]: %g --> %g\n", i, hrow[k], rdmin[i], bnd); #endif rdmin[i] = rmin = bnd; tightened ++; } } else if (coeff < -ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) { double bnd = djmin0 / coeff ; if (rmax > bnd) { #if PRESOLVE_DEBUG printf("MAX TIGHT1[%d,%d]: %g --> %g\n", i,hrow[k], rdmax[i], bnd); #endif rdmax[i] = rmax = bnd; tightened ++; } } } } } } #endif if (tightened<100||nfixdown_cols<ncols||nfixup_cols) break; #if PRESOLVE_TIGHTEN_DUALS else printf("DUAL TIGHTENED! %d\n", tightened); #endif } assert (nfixup_cols<=nfixdown_cols); if (nfixup_cols) { #if PRESOLVE_DEBUG printf("NDUAL: %d up", nfixup_cols); for (i = 0 ; i < nfixup_cols ; i++) printf(" %d",fix_cols[i]) ; printf(".\n") ; #endif next = make_fixed_action::presolve(prob, fix_cols, nfixup_cols, false, next); } if (nfixdown_cols<ncols) { int * fixdown_cols = fix_cols+nfixdown_cols; nfixdown_cols = ncols-nfixdown_cols; #if PRESOLVE_DEBUG printf("NDUAL: %d down", nfixdown_cols); for (i = 0 ; i < nfixdown_cols ; i++) printf(" %d",fixdown_cols[i]) ; printf(".\n") ; #endif next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols, true, next); } // If dual says so then we can make equality row // Also if cost is in right direction and only one binding row for variable // We may wish to think about giving preference to rows with 2 or 3 elements /* Gack! Ok, I can appreciate the thought here, but I'm seriously skeptical about writing canFix[0] before reading rdmin[0]. After that, we should be out of the interference zone for the typical situation where sizeof(double) is twice sizeof(int). */ int * canFix = reinterpret_cast<int *> (rdmin); for ( i = 0; i < nrows; i++) { bool no_lb = (rlo[i] <= -ekkinf); bool no_ub = (rup[i] >= ekkinf); canFix[i]=0; if (no_ub && !no_lb ) { if ( rdmin[i]>0.0) canFix[i]=-1; else canFix[i]=-2; } else if (no_lb && !no_ub ) { if (rdmax[i]<0.0) canFix[i]=1; else canFix[i]=2; } } for (j = 0; j<ncols; j++) { if (hincol[j]<=1) continue; if (integerType[j]) continue; // even if it has infinite bound now .... CoinBigIndex kcs = mcstrt[j]; CoinBigIndex kce = kcs + hincol[j]; int bindingUp=-1; int bindingDown=-1; if (cup[j]<ekkinf) bindingUp=-2; if (clo[j]>-ekkinf) bindingDown=-2; for (CoinBigIndex k = kcs; k < kce; k++) { int i = hrow[k]; if (abs(canFix[i])!=2) { bindingUp=-2; bindingDown=-2; break; } double coeff = colels[k]; if (coeff>0.0) { if (canFix[i]==2) { // binding up if (bindingUp==-1) bindingUp = i; else bindingUp = -2; } else { // binding down if (bindingDown==-1) bindingDown = i; else bindingDown = -2; } } else { if (canFix[i]==2) { // binding down if (bindingDown==-1) bindingDown = i; else bindingDown = -2; } else { // binding up if (bindingUp==-1) bindingUp = i; else bindingUp = -2; } } } double cost = maxmin * dcost[j]; if (bindingUp>-2&&cost<=0.0) { // might as well make equality if (bindingUp>=0) { canFix[bindingUp] /= 2; //So -2 goes to -1 etc //printf("fixing row %d to ub by %d\n",bindingUp,j); } else { //printf("binding up row by %d\n",j); } } else if (bindingDown>-2 &&cost>=0.0) { // might as well make equality if (bindingDown>=0) { canFix[bindingDown] /= 2; //So -2 goes to -1 etc //printf("fixing row %d to lb by %d\n",bindingDown,j); } else { //printf("binding down row by %d\n",j); } } } // can't fix if integer and non-unit coefficient //const double *rowels = prob->rowels_; //const int *hcol = prob->hcol_; //const CoinBigIndex *mrstrt = prob->mrstrt_; //int *hinrow = prob->hinrow_; for ( i = 0; i < nrows; i++) { if (abs(canFix[i])==1) { CoinBigIndex krs = mrstrt[i]; CoinBigIndex kre = krs + hinrow[i]; for (CoinBigIndex k=krs; k<kre; k++) { int icol = hcol[k]; if (cup[icol]>clo[icol]&&integerType[icol]) { canFix[i]=0; // not safe #ifdef COIN_DEVELOP printf("no dual something CoinPresolveDual row %d col %d\n", i,icol); #endif } } } if (canFix[i]==1) { rlo[i]=rup[i]; prob->addRow(i); } else if (canFix[i]==-1) { rup[i]=rlo[i]; prob->addRow(i); } } //delete[]rdmin; //delete[]rdmax; //delete[]fixup_cols; //delete[]fixdown_cols; #if PRESOLVE_TIGHTEN_DUALS delete[]djmin; delete[]djmax; #endif if (prob->tuning_) { double thisTime=CoinCpuTime(); int droppedRows = prob->countEmptyRows() - startEmptyRows; int droppedColumns = prob->countEmptyCols() - startEmptyColumns; printf("CoinPresolveDual(1) - %d rows, %d columns dropped in time %g, total %g\n", droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); } # if PRESOLVE_DEBUG presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; std::cout << "Leaving remove_dual_action::presolve." << std::endl ; # endif return (next); }
/* It is always the case that one of the variables of a doubleton is, or can be made, implied free, but neither will necessarily be a singleton. Since in the case of a doubleton the number of non-zero entries will never increase if one is eliminated, it makes sense to always eliminate them. The col rep and row rep must be consistent. */ const CoinPresolveAction *doubleton_action::presolve (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering doubleton_action::presolve; considering " << prob->numberRowsToDo_ << " rows." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0 ; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif const int n = prob->ncols_ ; const int m = prob->nrows_ ; /* Unpack column-major and row-major representations, along with rim vectors. */ CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; double *colCoeffs = prob->colels_ ; int *rowIndices = prob->hrow_ ; presolvehlink *clink = prob->clink_ ; double *clo = prob->clo_ ; double *cup = prob->cup_ ; CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; double *rowCoeffs = prob->rowels_ ; int *colIndices = prob->hcol_ ; presolvehlink *rlink = prob->rlink_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; const unsigned char *integerType = prob->integerType_ ; double *cost = prob->cost_ ; int numberLook = prob->numberRowsToDo_ ; int *look = prob->rowsToDo_ ; const double ztolzb = prob->ztolzb_ ; const double ztolzero = 1.0e-12 ; action *actions = new action [m] ; int nactions = 0 ; /* zeros will hold columns that should be groomed to remove explicit zeros when we're finished. fixed will hold columns that have ended up as fixed variables. */ int *zeros = prob->usefulColumnInt_ ; int nzeros = 0 ; int *fixed = zeros+n ; int nfixed = 0 ; unsigned char *rowstat = prob->rowstat_ ; double *acts = prob->acts_ ; double *sol = prob->sol_ ; /* More like `ignore infeasibility'. */ bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; /* Open the main loop to scan for doubleton candidates. */ for (int iLook = 0 ; iLook < numberLook ; iLook++) { const int tgtrow = look[iLook] ; /* We need an equality with two coefficients. Avoid isolated constraints, lest both variables vanish. Failure of the assert indicates that the row- and column-major representations are out of sync. */ if ((rowLengths[tgtrow] != 2) || (fabs(rup[tgtrow]-rlo[tgtrow]) > ZTOLDP)) continue ; const CoinBigIndex krs = rowStarts[tgtrow] ; int tgtcolx = colIndices[krs] ; int tgtcoly = colIndices[krs+1] ; PRESOLVEASSERT(colLengths[tgtcolx] > 0 || colLengths[tgtcoly] > 0) ; if (colLengths[tgtcolx] == 1 && colLengths[tgtcoly] == 1) continue ; /* Avoid prohibited columns and fixed columns. Make sure the coefficients are nonzero. JJF - test should allow one to be prohibited as long as you leave that one. I modified earlier code but hope I have got this right. */ if (prob->colProhibited(tgtcolx) && prob->colProhibited(tgtcoly)) continue ; if (fabs(rowCoeffs[krs]) < ZTOLDP2 || fabs(rowCoeffs[krs+1]) < ZTOLDP2) continue ; if ((fabs(cup[tgtcolx]-clo[tgtcolx]) < ZTOLDP) || (fabs(cup[tgtcoly]-clo[tgtcoly]) < ZTOLDP)) continue ; # if PRESOLVE_DEBUG > 2 std::cout << " row " << tgtrow << " colx " << tgtcolx << " coly " << tgtcoly << " passes preliminary eval." << std::endl ; # endif /* Find this row in each column. The indices are not const because we may flip them below, once we decide which column will be eliminated. */ CoinBigIndex krowx = presolve_find_row(tgtrow,colStarts[tgtcolx], colStarts[tgtcolx]+colLengths[tgtcolx],rowIndices) ; double coeffx = colCoeffs[krowx] ; CoinBigIndex krowy = presolve_find_row(tgtrow,colStarts[tgtcoly], colStarts[tgtcoly]+colLengths[tgtcoly],rowIndices) ; double coeffy = colCoeffs[krowy] ; const double rhs = rlo[tgtrow] ; /* Avoid obscuring a requirement for integrality. If only one variable is integer, keep it and substitute for the continuous variable. If both are integer, substitute only for the forms x = k*y (k integral and non-empty intersection on bounds on x) or x = 1-y, where both x and y are binary. flag bits for integerStatus: 0x01: x integer; 0x02: y integer This bit of code works because 0 is continuous, 1 is integer. Make sure that's true. */ assert((integerType[tgtcolx] == 0) || (integerType[tgtcolx] == 1)) ; assert((integerType[tgtcoly] == 0) || (integerType[tgtcoly] == 1)) ; int integerX = integerType[tgtcolx]; int integerY = integerType[tgtcoly]; /* if one prohibited then treat that as integer. This may be pessimistic - but will catch SOS etc */ if (prob->colProhibited2(tgtcolx)) integerX=1; if (prob->colProhibited2(tgtcoly)) integerY=1; int integerStatus = (integerY<<1)|integerX ; if (integerStatus == 3) { int good = 0 ; double rhs2 = rhs ; if (coeffx < 0.0) { coeffx = -coeffx ; rhs2 += 1 ; } if ((cup[tgtcolx] == 1.0) && (clo[tgtcolx] == 0.0) && (fabs(coeffx-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcoly)) good = 1 ; if (coeffy < 0.0) { coeffy = -coeffy ; rhs2 += 1 ; } if ((cup[tgtcoly] == 1.0) && (clo[tgtcoly] == 0.0) && (fabs(coeffy-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcolx)) good |= 2 ; if (!(good == 3 && fabs(rhs2-1.0) < 1.0e-7)) integerStatus = -1 ; /* Not x+y = 1. Try for ax+by = 0 */ if (integerStatus < 0 && rhs == 0.0) { coeffx = colCoeffs[krowx] ; coeffy = colCoeffs[krowy] ; double ratio ; bool swap = false ; if (fabs(coeffx) > fabs(coeffy)) { ratio = coeffx/coeffy ; } else { ratio = coeffy/coeffx ; swap = true ; } ratio = fabs(ratio) ; if (fabs(ratio-floor(ratio+0.5)) < ztolzero) { integerStatus = swap ? 2 : 1 ; } } /* One last try --- just require an integral substitution formula. But ax+by = 0 above is a subset of ax+by = c below and should pass the test below. For that matter, so will x+y = 1. Why separate special cases above? -- lh, 121106 -- */ if (integerStatus < 0) { bool canDo = false ; coeffx = colCoeffs[krowx] ; coeffy = colCoeffs[krowy] ; double ratio ; bool swap = false ; double rhsRatio ; if (fabs(coeffx) > fabs(coeffy)) { ratio = coeffx/coeffy ; rhsRatio = rhs/coeffx ; } else { ratio = coeffy/coeffx ; rhsRatio = rhs/coeffy ; swap = true ; } ratio = fabs(ratio) ; if (fabs(ratio-floor(ratio+0.5)) < ztolzero) { // possible integerStatus = swap ? 2 : 1 ; // but check rhs if (rhsRatio==floor(rhsRatio+0.5)) canDo=true ; } # ifdef COIN_DEVELOP2 if (canDo) printf("Good CoinPresolveDoubleton tgtcolx %d (%g and bounds %g %g) tgtcoly %d (%g and bound %g %g) - rhs %g\n", tgtcolx,colCoeffs[krowx],clo[tgtcolx],cup[tgtcolx], tgtcoly,colCoeffs[krowy],clo[tgtcoly],cup[tgtcoly],rhs) ; else printf("Bad CoinPresolveDoubleton tgtcolx %d (%g) tgtcoly %d (%g) - rhs %g\n", tgtcolx,colCoeffs[krowx],tgtcoly,colCoeffs[krowy],rhs) ; # endif if (!canDo) continue ; } } /* We've resolved integrality concerns. If we concluded that we need to switch the roles of x and y because of integrality, do that now. If both variables are continuous, we may still want to swap for numeric stability. Eliminate the variable with the larger coefficient. */ if (integerStatus == 2) { CoinSwap(tgtcoly,tgtcolx) ; CoinSwap(krowy,krowx) ; } else if (integerStatus == 0) { if (fabs(colCoeffs[krowy]) < fabs(colCoeffs[krowx])) { CoinSwap(tgtcoly,tgtcolx) ; CoinSwap(krowy,krowx) ; } } /* Don't eliminate y just yet if it's entangled in a singleton row (we want to capture that explicit bound in a column bound). */ const CoinBigIndex kcsy = colStarts[tgtcoly] ; const CoinBigIndex kcey = kcsy+colLengths[tgtcoly] ; bool singletonRow = false ; for (CoinBigIndex kcol = kcsy ; kcol < kcey ; kcol++) { if (rowLengths[rowIndices[kcol]] == 1) { singletonRow = true ; break ; } } // skip if y prohibited if (singletonRow || prob->colProhibited2(tgtcoly)) continue ; coeffx = colCoeffs[krowx] ; coeffy = colCoeffs[krowy] ; # if PRESOLVE_DEBUG > 2 std::cout << " doubleton row " << tgtrow << ", keep x(" << tgtcolx << ") elim x(" << tgtcoly << ")." << std::endl ; # endif PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n", tgtcoly,tgtcolx,tgtrow)) ; /* Capture the existing columns and other information before we start to modify the constraint system. Save the shorter column. */ action *s = &actions[nactions] ; nactions++ ; s->row = tgtrow ; s->icolx = tgtcolx ; s->clox = clo[tgtcolx] ; s->cupx = cup[tgtcolx] ; s->costx = cost[tgtcolx] ; s->icoly = tgtcoly ; s->costy = cost[tgtcoly] ; s->rlo = rlo[tgtrow] ; s->coeffx = coeffx ; s->coeffy = coeffy ; s->ncolx = colLengths[tgtcolx] ; s->ncoly = colLengths[tgtcoly] ; if (s->ncoly < s->ncolx) { s->colel = presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcoly], colStarts[tgtcoly],tgtrow) ; s->ncolx = 0 ; } else { s->colel = presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcolx], colStarts[tgtcolx],tgtrow) ; s->ncoly = 0 ; } /* Move finite bound information from y to x, so that y is implied free. a x + b y = c l1 <= x <= u1 l2 <= y <= u2 l2 <= (c - a x) / b <= u2 b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a */ { double lo1 = -PRESOLVE_INF ; double up1 = PRESOLVE_INF ; if (-PRESOLVE_INF < clo[tgtcoly]) { if (coeffx*coeffy < 0) lo1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ; else up1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ; } if (cup[tgtcoly] < PRESOLVE_INF) { if (coeffx*coeffy < 0) up1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ; else lo1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ; } /* Don't forget the objective coefficient. costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b */ cost[tgtcolx] += (cost[tgtcoly]*-coeffx)/coeffy ; prob->change_bias((cost[tgtcoly]*rhs)/coeffy) ; /* The transfer of bounds could make x infeasible. Patch it up if the problem is minor or if the user was so incautious as to instruct us to ignore it. Prefer an integer value if there's one nearby. If there's nothing to be done, break out of the main loop. */ { double lo2 = CoinMax(clo[tgtcolx],lo1) ; double up2 = CoinMin(cup[tgtcolx],up1) ; if (lo2 > up2) { if (lo2 <= up2+prob->feasibilityTolerance_ || fixInfeasibility) { double nearest = floor(lo2+0.5) ; if (fabs(nearest-lo2) < 2.0*prob->feasibilityTolerance_) { lo2 = nearest ; up2 = nearest ; } else { lo2 = up2 ; } } else { prob->status_ |= 1 ; prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, prob->messages()) << tgtcolx << lo2 << up2 << CoinMessageEol ; break ; } } # if PRESOLVE_DEBUG > 2 std::cout << " x(" << tgtcolx << ") lb " << clo[tgtcolx] << " --> " << lo2 << ", ub " << cup[tgtcolx] << " --> " << up2 << std::endl ; # endif clo[tgtcolx] = lo2 ; cup[tgtcolx] = up2 ; /* Do we have a solution to maintain? If so, take a stab at it. If x ends up at bound, prefer to set it nonbasic, but if we're short of basic variables after eliminating y and the logical for the row, make it basic. This code will snap the value of x to bound if it's within the primal feasibility tolerance. */ if (rowstat && sol) { int numberBasic = 0 ; double movement = 0 ; if (prob->columnIsBasic(tgtcolx)) numberBasic++ ; if (prob->columnIsBasic(tgtcoly)) numberBasic++ ; if (prob->rowIsBasic(tgtrow)) numberBasic++ ; if (sol[tgtcolx] <= lo2+ztolzb) { movement = lo2-sol[tgtcolx] ; sol[tgtcolx] = lo2 ; prob->setColumnStatus(tgtcolx, CoinPrePostsolveMatrix::atLowerBound) ; } else if (sol[tgtcolx] >= up2-ztolzb) { movement = up2-sol[tgtcolx] ; sol[tgtcolx] = up2 ; prob->setColumnStatus(tgtcolx, CoinPrePostsolveMatrix::atUpperBound) ; } if (numberBasic > 1) prob->setColumnStatus(tgtcolx,CoinPrePostsolveMatrix::basic) ; /* We need to compensate if x was forced to move. Beyond that, even if x didn't move, we've forced y = (c-ax)/b, and that might not have been true before. So even if x didn't move, y may have moved. Note that the constant term c/b is subtracted out as the constraints are modified, so we don't include it when calculating movement for y. */ if (movement) { const CoinBigIndex kkcsx = colStarts[tgtcolx] ; const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ; for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) { int row = rowIndices[kcol] ; if (rowLengths[row]) acts[row] += movement*colCoeffs[kcol] ; } } movement = ((-coeffx*sol[tgtcolx])/coeffy)-sol[tgtcoly] ; if (movement) { const CoinBigIndex kkcsy = colStarts[tgtcoly] ; const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ; for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) { int row = rowIndices[kcol] ; if (rowLengths[row]) acts[row] += movement*colCoeffs[kcol] ; } } } if (lo2 == up2) fixed[nfixed++] = tgtcolx ; } } /* We're done transferring bounds from y to x, and we've patched up the solution if one existed to patch. One last thing to do before we eliminate column y and the doubleton row: put column x and the entangled rows on the lists of columns and rows to look at in the next round of transforms. */ { prob->addCol(tgtcolx) ; const CoinBigIndex kkcsy = colStarts[tgtcoly] ; const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ; for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) { int row = rowIndices[kcol] ; prob->addRow(row) ; } const CoinBigIndex kkcsx = colStarts[tgtcolx] ; const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ; for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) { int row = rowIndices[kcol] ; prob->addRow(row) ; } } /* Empty tgtrow in the column-major matrix. Deleting the coefficient for (tgtrow,tgtcoly) is a bit costly (given that we're about to drop the whole column), but saves the trouble of checking for it in elim_doubleton. */ presolve_delete_from_col(tgtrow,tgtcolx, colStarts,colLengths,rowIndices,colCoeffs) ; presolve_delete_from_col(tgtrow,tgtcoly, colStarts,colLengths,rowIndices,colCoeffs) ; /* Drop tgtrow in the row-major representation: set the length to 0 and reclaim the major vector space in bulk storage. */ rowLengths[tgtrow] = 0 ; PRESOLVE_REMOVE_LINK(rlink,tgtrow) ; /* Transfer the colx factors to coly. This modifies coefficients in column x as it removes coefficients in column y. */ bool no_mem = elim_doubleton("ELIMD", colStarts,rlo,rup,colCoeffs, rowIndices,colIndices,rowLengths,colLengths, clink,n, rowStarts,rowCoeffs, -coeffx/coeffy, rhs/coeffy, tgtrow,tgtcolx,tgtcoly) ; if (no_mem) throwCoinError("out of memory","doubleton_action::presolve") ; /* Eliminate coly entirely from the col rep. We'll want to groom colx to remove explicit zeros. */ colLengths[tgtcoly] = 0 ; PRESOLVE_REMOVE_LINK(clink, tgtcoly) ; cost[tgtcoly] = 0.0 ; rlo[tgtrow] = 0.0 ; rup[tgtrow] = 0.0 ; zeros[nzeros++] = tgtcolx ; # if PRESOLVE_CONSISTENCY > 0 presolve_consistent(prob) ; presolve_links_ok(prob) ; # endif } /* Tidy up the collected actions and clean up explicit zeros and fixed variables. Don't bother unless we're feasible (status of 0). */ if (nactions && !prob->status_) { # if PRESOLVE_SUMMARY > 0 printf("NDOUBLETONS: %d\n", nactions) ; # endif action *actions1 = new action[nactions] ; CoinMemcpyN(actions, nactions, actions1) ; next = new doubleton_action(nactions, actions1, next) ; if (nzeros) next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next) ; if (nfixed) next = remove_fixed_action::presolve(prob, fixed, nfixed, next) ; } deleteAction(actions,action*) ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_sol(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving doubleton_action::presolve, " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
/* It may be the case that the bounds on the variables in a constraint are such that no matter what feasible value the variables take, the constraint cannot be violated. In this case we can drop the constraint as useless. On the other hand, it may be that the only way to satisfy a constraint is to jam all the variables in the constraint to one of their bounds, fixing the variables. This is a forcing constraint, the primary target of this transform. Detection of both useless and forcing constraints requires calculation of bounds on the row activity (often referred to as lhs bounds, from the common form ax <= b). This routine will remember useless constraints as it finds them and invoke useless_constraint_action to deal with them. The transform applied here simply tightens the bounds on the variables. Other transforms will remove the fixed variables, leaving an empty row which is ultimately dropped. A reasonable question to ask is ``If a variable is already fixed, why do we need a record in the postsolve object?'' The answer is that in postsolve we'll be dealing with a column-major representation and we may need to scan the row (see postsolve comments). So it's useful to record all variables in the constraint. On the other hand, it's definitely harmful to ask remove_fixed_action to process a variable more than once (causes problems in remove_fixed_action::postsolve). Original comments: It looks like these checks could be performed in parallel, that is, the tests could be carried out for all rows in parallel, and then the rows deleted and columns tightened afterward. Obviously, this is true for useless rows. By doing it in parallel rather than sequentially, we may miss transformations due to variables that were fixed by forcing constraints, though. Note that both of these operations will cause problems if the variables in question really need to exceed their bounds in order to make the problem feasible. */ const CoinPresolveAction* forcing_constraint_action::presolve (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # endif # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering forcing_constraint_action::presolve, considering " << prob->numberRowsToDo_ << " rows." << std::endl ; # endif presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if COIN_PRESOLVE_TUNING double startTime = 0.0 ; if (prob->tuning_) { startTime = CoinCpuTime() ; } # endif // Column solution and bounds double *clo = prob->clo_ ; double *cup = prob->cup_ ; double *csol = prob->sol_ ; // Row-major representation const CoinBigIndex *mrstrt = prob->mrstrt_ ; const double *rowels = prob->rowels_ ; const int *hcol = prob->hcol_ ; const int *hinrow = prob->hinrow_ ; const int nrows = prob->nrows_ ; const double *rlo = prob->rlo_ ; const double *rup = prob->rup_ ; const double tol = ZTOLDP ; const double inftol = prob->feasibilityTolerance_ ; // for redundant rows be safe const double inftol2 = 0.01*prob->feasibilityTolerance_ ; const int ncols = prob->ncols_ ; int *fixed_cols = new int[ncols] ; int nfixed_cols = 0 ; action *actions = new action [nrows] ; int nactions = 0 ; int *useless_rows = new int[nrows] ; int nuseless_rows = 0 ; const int numberLook = prob->numberRowsToDo_ ; int *look = prob->rowsToDo_ ; bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; /* Open a loop to scan the constraints of interest. There must be variables left in the row. */ for (int iLook = 0 ; iLook < numberLook ; iLook++) { int irow = look[iLook] ; if (hinrow[irow] <= 0) continue ; const CoinBigIndex krs = mrstrt[irow] ; const CoinBigIndex kre = krs+hinrow[irow] ; /* Calculate upper and lower bounds on the row activity based on upper and lower bounds on the variables. If these are finite and incompatible with the given row bounds, we have infeasibility. */ double maxup, maxdown ; implied_row_bounds(rowels,clo,cup,hcol,krs,kre,maxup,maxdown) ; # if PRESOLVE_DEBUG > 2 std::cout << " considering row " << irow << ", rlo " << rlo[irow] << " LB " << maxdown << " UB " << maxup << " rup " << rup[irow] ; # endif /* If the maximum lhs value is less than L(i) or the minimum lhs value is greater than U(i), we're infeasible. */ if (maxup < PRESOLVE_INF && maxup+inftol < rlo[irow] && !fixInfeasibility) { CoinMessageHandler *hdlr = prob->messageHandler() ; prob->status_|= 1 ; hdlr->message(COIN_PRESOLVE_ROWINFEAS,prob->messages()) << irow << rlo[irow] << rup[irow] << CoinMessageEol ; # if PRESOLVE_DEBUG > 2 std::cout << "; infeasible." << std::endl ; # endif break ; } if (-PRESOLVE_INF < maxdown && rup[irow] < maxdown-inftol && !fixInfeasibility) { CoinMessageHandler *hdlr = prob->messageHandler() ; prob->status_|= 1 ; hdlr->message(COIN_PRESOLVE_ROWINFEAS,prob->messages()) << irow << rlo[irow] << rup[irow] << CoinMessageEol ; # if PRESOLVE_DEBUG > 2 std::cout << "; infeasible." << std::endl ; # endif break ; } /* We've dealt with prima facie infeasibility. Now check if the constraint is trivially satisfied. If so, add it to the list of useless rows and move on. The reason we require maxdown and maxup to be finite if the row bound is finite is to guard against some subsequent transform changing a column bound from infinite to finite. Once finite, bounds continue to tighten, so we're safe. */ /* Test changed to use +small tolerance rather than -tolerance as test fails often */ if (((rlo[irow] <= -PRESOLVE_INF) || (-PRESOLVE_INF < maxdown && rlo[irow] <= maxdown+inftol2)) && ((rup[irow] >= PRESOLVE_INF) || (maxup < PRESOLVE_INF && rup[irow] >= maxup-inftol2))) { // check none prohibited if (prob->anyProhibited_) { bool anyProhibited=false; for (int k=krs; k<kre; k++) { int jcol = hcol[k]; if (prob->colProhibited(jcol)) { anyProhibited=true; break; } } if (anyProhibited) continue; // skip row } useless_rows[nuseless_rows++] = irow ; # if PRESOLVE_DEBUG > 2 std::cout << "; useless." << std::endl ; # endif continue ; } /* Is it the case that we can just barely attain L(i) or U(i)? If so, we have a forcing constraint. As explained above, we need maxup and maxdown to be finite in order for the test to be valid. */ const bool tightAtLower = ((maxup < PRESOLVE_INF) && (fabs(rlo[irow]-maxup) < tol)) ; const bool tightAtUpper = ((-PRESOLVE_INF < maxdown) && (fabs(rup[irow]-maxdown) < tol)) ; # if PRESOLVE_DEBUG > 2 if (tightAtLower || tightAtUpper) std::cout << "; forcing." ; std::cout << std::endl ; # endif if (!(tightAtLower || tightAtUpper)) continue ; // check none prohibited if (prob->anyProhibited_) { bool anyProhibited=false; for (int k=krs; k<kre; k++) { int jcol = hcol[k]; if (prob->colProhibited(jcol)) { anyProhibited=true; break; } } if (anyProhibited) continue; // skip row } /* We have a forcing constraint. Get down to the business of fixing the variables at the appropriate bound. We need to remember the original value of the bound we're tightening. Allocate a pair of arrays the size of the row. Load variables fixed at l<j> from the start, variables fixed at u<j> from the end. Add the column to the list of columns to be processed further. */ double *bounds = new double[hinrow[irow]] ; int *rowcols = new int[hinrow[irow]] ; CoinBigIndex lk = krs ; CoinBigIndex uk = kre ; for (CoinBigIndex k = krs ; k < kre ; k++) { const int j = hcol[k] ; const double lj = clo[j] ; const double uj = cup[j] ; const double coeff = rowels[k] ; PRESOLVEASSERT(fabs(coeff) > ZTOLDP) ; /* If maxup is tight at L(i), then we want to force variables x<j> to the bound that produced maxup: u<j> if a<ij> > 0, l<j> if a<ij> < 0. If maxdown is tight at U(i), it'll be just the opposite. */ if (tightAtLower == (coeff > 0.0)) { --uk ; bounds[uk-krs] = lj ; rowcols[uk-krs] = j ; if (csol != 0) { csol[j] = uj ; } clo[j] = uj ; } else { bounds[lk-krs] = uj ; rowcols[lk-krs] = j ; ++lk ; if (csol != 0) { csol[j] = lj ; } cup[j] = lj ; } /* Only add a column to the list of fixed columns the first time it's fixed. */ if (lj != uj) { fixed_cols[nfixed_cols++] = j ; prob->addCol(j) ; } } PRESOLVEASSERT(uk == lk) ; PRESOLVE_DETAIL_PRINT(printf("pre_forcing %dR E\n",irow)) ; # if PRESOLVE_DEBUG > 1 std::cout << "FORCING: row(" << irow << "), " << (kre-krs) << " variables." << std::endl ; # endif /* Done with this row. Remember the changes in a postsolve action. */ action *f = &actions[nactions] ; nactions++ ; f->row = irow ; f->nlo = lk-krs ; f->nup = kre-uk ; f->rowcols = rowcols ; f->bounds = bounds ; } /* Done processing the rows of interest. No sense doing any additional work unless we're feasible. */ if (prob->status_ == 0) { # if PRESOLVE_DEBUG > 0 std::cout << "FORCING: " << nactions << " forcing, " << nuseless_rows << " useless." << std::endl ; # endif /* Trim the actions array to size and create a postsolve object. */ if (nactions) { next = new forcing_constraint_action(nactions, CoinCopyOfArray(actions,nactions),next) ; } /* Hand off the job of dealing with the useless rows to a specialist. */ if (nuseless_rows) { next = useless_constraint_action::presolve(prob, useless_rows,nuseless_rows,next) ; } /* Hand off the job of dealing with the fixed columns to a specialist. Note that there *cannot* be duplicates in this list or we'll get in trouble `unfixing' a column multiple times. The code above now adds a variable to fixed_cols only if it's not already fixed. If that ever changes, the disabled code (sort, unique) will need to be reenabled. */ if (nfixed_cols) { if (false && nfixed_cols > 1) { std::sort(fixed_cols,fixed_cols+nfixed_cols) ; int *end = std::unique(fixed_cols,fixed_cols+nfixed_cols) ; nfixed_cols = static_cast<int>(end-fixed_cols) ; } next = remove_fixed_action::presolve(prob,fixed_cols,nfixed_cols,next) ; } } else { // delete arrays for (int i=0;i<nactions;i++) { deleteAction(actions[i].rowcols,int *) ; deleteAction(actions[i].bounds,double *) ; } } deleteAction(actions,action*) ; delete [] useless_rows ; delete [] fixed_cols ; # if COIN_PRESOLVE_TUNING if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving forcing_constraint_action::presolve: removed " << droppedRows << " rows, " << droppedColumns << " columns" ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) std::cout << " in " << (thisTime-prob->startTime_) << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
/* * * The col rep and row rep must be consistent. */ const CoinPresolveAction *tripleton_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double startTime = 0.0; int startEmptyRows=0; int startEmptyColumns = 0; if (prob->tuning_) { startTime = CoinCpuTime(); startEmptyRows = prob->countEmptyRows(); startEmptyColumns = prob->countEmptyCols(); } double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int ncols = prob->ncols_; double *clo = prob->clo_; double *cup = prob->cup_; double *rowels = prob->rowels_; int *hcol = prob->hcol_; CoinBigIndex *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; int nrows = prob->nrows_; double *rlo = prob->rlo_; double *rup = prob->rup_; presolvehlink *clink = prob->clink_; presolvehlink *rlink = prob->rlink_; const unsigned char *integerType = prob->integerType_; double *cost = prob->cost_; int numberLook = prob->numberRowsToDo_; int iLook; int * look = prob->rowsToDo_; const double ztolzb = prob->ztolzb_; action * actions = new action [nrows]; # ifdef ZEROFAULT // initialise alignment padding bytes memset(actions,0,nrows*sizeof(action)) ; # endif int nactions = 0; int *zeros = prob->usefulColumnInt_; //new int[ncols]; char * mark = reinterpret_cast<char *>(zeros+ncols); memset(mark,0,ncols); int nzeros = 0; // If rowstat exists then all do unsigned char *rowstat = prob->rowstat_; double *acts = prob->acts_; // unsigned char * colstat = prob->colstat_; # if PRESOLVE_CONSISTENCY presolve_links_ok(prob) ; # endif // wasfor (int irow=0; irow<nrows; irow++) for (iLook=0;iLook<numberLook;iLook++) { int irow = look[iLook]; if (hinrow[irow] == 3 && fabs(rup[irow] - rlo[irow]) <= ZTOLDP) { double rhs = rlo[irow]; CoinBigIndex krs = mrstrt[irow]; CoinBigIndex kre = krs + hinrow[irow]; int icolx, icoly, icolz; double coeffx, coeffy, coeffz; CoinBigIndex k; /* locate first column */ for (k=krs; k<kre; k++) { if (hincol[hcol[k]] > 0) { break; } } PRESOLVEASSERT(k<kre); coeffx = rowels[k]; if (fabs(coeffx) < ZTOLDP2) continue; icolx = hcol[k]; /* locate second column */ for (k++; k<kre; k++) { if (hincol[hcol[k]] > 0) { break; } } PRESOLVEASSERT(k<kre); coeffy = rowels[k]; if (fabs(coeffy) < ZTOLDP2) continue; icoly = hcol[k]; /* locate third column */ for (k++; k<kre; k++) { if (hincol[hcol[k]] > 0) { break; } } PRESOLVEASSERT(k<kre); coeffz = rowels[k]; if (fabs(coeffz) < ZTOLDP2) continue; icolz = hcol[k]; // For now let's do obvious one if (coeffx*coeffz>0.0) { if(coeffx*coeffy>0.0) continue; } else if (coeffx*coeffy>0.0) { int iTemp = icoly; icoly=icolz; icolz=iTemp; double dTemp = coeffy; coeffy=coeffz; coeffz=dTemp; } else { int iTemp = icoly; icoly=icolx; icolx=iTemp; double dTemp = coeffy; coeffy=coeffx; coeffx=dTemp; } // Not all same sign and y is odd one out // don't bother with fixed variables if (!(fabs(cup[icolx] - clo[icolx]) < ZTOLDP) && !(fabs(cup[icoly] - clo[icolx]) < ZTOLDP) && !(fabs(cup[icolz] - clo[icoly]) < ZTOLDP)) { assert (coeffx*coeffz>0.0&&coeffx*coeffy<0.0); // Only do if does not give implicit bounds on x and z double cx = - coeffx/coeffy; double cz = - coeffz/coeffy; /* don't do if y integer for now */ if (integerType[icoly]) { #define PRESOLVE_DANGEROUS #ifndef PRESOLVE_DANGEROUS continue; #else if (!integerType[icolx]||!integerType[icolz]) continue; if (cx!=floor(cx+0.5)||cz!=floor(cz+0.5)) continue; #endif } double rhsRatio = rhs/coeffy; if (clo[icoly]>-1.0e30) { if (clo[icolx]<-1.0e30||clo[icolz]<-1.0e30) continue; if (cx*clo[icolx]+cz*clo[icolz]+rhsRatio<clo[icoly]-ztolzb) continue; } if (cup[icoly]<1.0e30) { if (cup[icolx]>1.0e30||cup[icolz]>1.0e30) continue; if (cx*cup[icolx]+cz*cup[icolz]+rhsRatio>cup[icoly]+ztolzb) continue; } CoinBigIndex krowx,krowy,krowz; /* find this row in each of the columns and do counts */ bool singleton=false; for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) { int jrow=hrow[k]; if (hinrow[jrow]==1) singleton=true; if (jrow == irow) krowy=k; else prob->setRowUsed(jrow); } int nDuplicate=0; for (k=mcstrt[icolx]; k<mcstrt[icolx]+hincol[icolx]; k++) { int jrow=hrow[k]; if (jrow == irow) krowx=k; else if (prob->rowUsed(jrow)) nDuplicate++;; } for (k=mcstrt[icolz]; k<mcstrt[icolz]+hincol[icolz]; k++) { int jrow=hrow[k]; if (jrow == irow) krowz=k; else if (prob->rowUsed(jrow)) nDuplicate++;; } int nAdded=hincol[icoly]-3-nDuplicate; for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) { int jrow=hrow[k]; prob->unsetRowUsed(jrow); } // let singleton rows be taken care of first if (singleton) continue; //if (nAdded<=1) //printf("%d elements added, hincol %d , dups %d\n",nAdded,hincol[icoly],nDuplicate); if (nAdded>2) continue; // it is possible that both x/z and y are singleton columns // that can cause problems if ((hincol[icolx] == 1 ||hincol[icolz] == 1) && hincol[icoly] == 1) continue; // common equations are of the form ax + by = 0, or x + y >= lo { action *s = &actions[nactions]; nactions++; PRESOLVE_DETAIL_PRINT(printf("pre_tripleton %dR %dC %dC %dC E\n", irow,icoly,icolx,icolz)); s->row = irow; s->icolx = icolx; s->icolz = icolz; s->icoly = icoly; s->cloy = clo[icoly]; s->cupy = cup[icoly]; s->costy = cost[icoly]; s->rlo = rlo[irow]; s->rup = rup[irow]; s->coeffx = coeffx; s->coeffy = coeffy; s->coeffz = coeffz; s->ncoly = hincol[icoly]; s->colel = presolve_dupmajor(colels, hrow, hincol[icoly], mcstrt[icoly]); } // costs // the effect of maxmin cancels out cost[icolx] += cost[icoly] * cx; cost[icolz] += cost[icoly] * cz; prob->change_bias(cost[icoly] * rhs / coeffy); //if (cost[icoly]*rhs) //printf("change %g col %d cost %g rhs %g coeff %g\n",cost[icoly]*rhs/coeffy, // icoly,cost[icoly],rhs,coeffy); if (rowstat) { // update solution and basis int numberBasic=0; if (prob->columnIsBasic(icoly)) numberBasic++; if (prob->rowIsBasic(irow)) numberBasic++; if (numberBasic>1) { if (!prob->columnIsBasic(icolx)) prob->setColumnStatus(icolx,CoinPrePostsolveMatrix::basic); else prob->setColumnStatus(icolz,CoinPrePostsolveMatrix::basic); } } // Update next set of actions { prob->addCol(icolx); int i,kcs,kce; kcs = mcstrt[icoly]; kce = kcs + hincol[icoly]; for (i=kcs;i<kce;i++) { int row = hrow[i]; prob->addRow(row); } kcs = mcstrt[icolx]; kce = kcs + hincol[icolx]; for (i=kcs;i<kce;i++) { int row = hrow[i]; prob->addRow(row); } prob->addCol(icolz); kcs = mcstrt[icolz]; kce = kcs + hincol[icolz]; for (i=kcs;i<kce;i++) { int row = hrow[i]; prob->addRow(row); } } /* transfer the colx factors to coly */ bool no_mem = elim_tripleton("ELIMT", mcstrt, rlo, acts, rup, colels, hrow, hcol, hinrow, hincol, clink, ncols, rlink, nrows, mrstrt, rowels, cx, cz, rhs / coeffy, irow, icolx, icoly,icolz); if (no_mem) throwCoinError("out of memory", "tripleton_action::presolve"); // now remove irow from icolx and icolz in the col rep // better if this were first. presolve_delete_from_col(irow,icolx,mcstrt,hincol,hrow,colels) ; presolve_delete_from_col(irow,icolz,mcstrt,hincol,hrow,colels) ; // eliminate irow entirely from the row rep hinrow[irow] = 0; // eliminate irow entirely from the row rep PRESOLVE_REMOVE_LINK(rlink, irow); // eliminate coly entirely from the col rep PRESOLVE_REMOVE_LINK(clink, icoly); cost[icoly] = 0.0; rlo[irow] = 0.0; rup[irow] = 0.0; if (!mark[icolx]) { mark[icolx]=1; zeros[nzeros++]=icolx; } if (!mark[icolz]) { mark[icolz]=1; zeros[nzeros++]=icolz; } } # if PRESOLVE_CONSISTENCY presolve_links_ok(prob) ; presolve_consistent(prob); # endif } } if (nactions) { # if PRESOLVE_SUMMARY printf("NTRIPLETONS: %d\n", nactions); # endif action *actions1 = new action[nactions]; CoinMemcpyN(actions, nactions, actions1); next = new tripleton_action(nactions, actions1, next); if (nzeros) { next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next); } } //delete[]zeros; deleteAction(actions,action*); if (prob->tuning_) { double thisTime=CoinCpuTime(); int droppedRows = prob->countEmptyRows() - startEmptyRows ; int droppedColumns = prob->countEmptyCols() - startEmptyColumns; printf("CoinPresolveTripleton(8) - %d rows, %d columns dropped in time %g, total %g\n", droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); } return (next); }
const CoinPresolveAction *do_tighten_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int ncols = prob->ncols_; double *clo = prob->clo_; double *cup = prob->cup_; double *rlo = prob->rlo_; double *rup = prob->rup_; double *dcost = prob->cost_; const unsigned char *integerType = prob->integerType_; int *fix_cols = prob->usefulColumnInt_; int nfixup_cols = 0; int nfixdown_cols = ncols; int *useless_rows = prob->usefulRowInt_; int nuseless_rows = 0; action *actions = new action [ncols]; int nactions = 0; int numberLook = prob->numberColsToDo_; int iLook; int * look = prob->colsToDo_; bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering do_tighten_action::presolve; considering " << numberLook << " rows." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif // singleton columns are especially likely to be caught here for (iLook=0;iLook<numberLook;iLook++) { int j = look[iLook]; // modify bounds if integer if (integerType[j]) { clo[j] = ceil(clo[j]-1.0e-12); cup[j] = floor(cup[j]+1.0e-12); if (clo[j]>cup[j]&&!fixInfeasibility) { // infeasible prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, prob->messages()) <<j <<clo[j] <<cup[j] <<CoinMessageEol; } } if (dcost[j]==0.0) { int iflag=0; /* 1 - up is towards feasibility, -1 down is towards */ int nonFree=0; // Number of non-free rows CoinBigIndex kcs = mcstrt[j]; CoinBigIndex kce = kcs + hincol[j]; // check constraints for (CoinBigIndex k=kcs; k<kce; ++k) { int i = hrow[k]; double coeff = colels[k]; double rlb = rlo[i]; double rub = rup[i]; if (-1.0e28 < rlb && rub < 1.0e28) { // bounded - we lose iflag=0; break; } else if (-1.0e28 < rlb || rub < 1.0e28) { nonFree++; } PRESOLVEASSERT(fabs(coeff) > ZTOLDP); // see what this particular row says // jflag == 1 ==> up is towards feasibility int jflag = (coeff > 0.0 ? (rub > 1.0e28 ? 1 : -1) : (rlb < -1.0e28 ? 1 : -1)); if (iflag) { // check that it agrees with iflag. if (iflag!=jflag) { iflag=0; break; } } else { // first row -- initialize iflag iflag=jflag; } } // done checking constraints if (!nonFree) iflag=0; // all free anyway if (iflag) { if (iflag==1 && cup[j]<1.0e10) { #if PRESOLVE_DEBUG > 1 printf("TIGHTEN UP: %d\n", j); #endif fix_cols[nfixup_cols++] = j; } else if (iflag==-1&&clo[j]>-1.0e10) { // symmetric case //mpre[j] = PRESOLVE_XUP; #if PRESOLVE_DEBUG > 1 printf("TIGHTEN DOWN: %d\n", j); #endif fix_cols[--nfixdown_cols] = j; } else { #if 0 static int limit; static int which = atoi(getenv("WZ")); if (which == -1) ; else if (limit != which) { limit++; continue; } else limit++; printf("TIGHTEN STATS %d %g %g %d: \n", j, clo[j], cup[j], integerType[j]); double *rowels = prob->rowels_; int *hcol = prob->hcol_; int *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; for (CoinBigIndex k=kcs; k<kce; ++k) { int irow = hrow[k]; CoinBigIndex krs = mrstrt[irow]; CoinBigIndex kre = krs + hinrow[irow]; printf("%d %g %g %g: ", irow, rlo[irow], rup[irow], colels[irow]); for (CoinBigIndex kk=krs; kk<kre; ++kk) printf("%d(%g) ", hcol[kk], rowels[kk]); printf("\n"); } #endif { action *s = &actions[nactions]; nactions++; s->col = j; PRESOLVE_DETAIL_PRINT(printf("pre_tighten %dC E\n",j)); if (integerType[j]) { assert (iflag==-1||iflag==1); iflag *= 2; // say integer } s->direction = iflag; s->rows = new int[hincol[j]]; s->lbound = new double[hincol[j]]; s->ubound = new double[hincol[j]]; #if PRESOLVE_DEBUG > 1 printf("TIGHTEN FREE: %d ", j); #endif int nr = 0; prob->addCol(j); for (CoinBigIndex k=kcs; k<kce; ++k) { int irow = hrow[k]; // ignore this if we've already made it useless if (! (rlo[irow] == -PRESOLVE_INF && rup[irow] == PRESOLVE_INF)) { prob->addRow(irow); s->rows [nr] = irow; s->lbound[nr] = rlo[irow]; s->ubound[nr] = rup[irow]; nr++; useless_rows[nuseless_rows++] = irow; rlo[irow] = -PRESOLVE_INF; rup[irow] = PRESOLVE_INF; #if PRESOLVE_DEBUG > 1 printf("%d ", irow); #endif } } s->nrows = nr; #if PRESOLVE_DEBUG > 1 printf("\n"); #endif } } } } } #if PRESOLVE_SUMMARY > 0 if (nfixdown_cols<ncols || nfixup_cols || nuseless_rows) { printf("NTIGHTENED: %d %d %d\n", ncols-nfixdown_cols, nfixup_cols, nuseless_rows); } #endif if (nuseless_rows) { next = new do_tighten_action(nactions, CoinCopyOfArray(actions,nactions), next); next = useless_constraint_action::presolve(prob, useless_rows, nuseless_rows, next); } deleteAction(actions, action*); //delete[]useless_rows; if (nfixdown_cols<ncols) { int * fixdown_cols = fix_cols+nfixdown_cols; nfixdown_cols = ncols-nfixdown_cols; next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols, true, next); } //delete[]fixdown_cols; if (nfixup_cols) { next = make_fixed_action::presolve(prob, fix_cols, nfixup_cols, false, next); } //delete[]fixup_cols; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_sol(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving do_tighten_action::presolve, " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next); }
const CoinPresolveAction *subst_constraint_action::presolve ( CoinPresolveMatrix *prob, const int *implied_free, const int *whichFree, int numberFree, const CoinPresolveAction *next, int maxLook) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering subst_constraint_action::presolve, fill level " << maxLook << ", " << numberFree << " candidates." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0 ; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif /* Unpack the row- and column-major representations. */ const int ncols = prob->ncols_ ; const int nrows = prob->nrows_ ; CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; double *rowCoeffs = prob->rowels_ ; int *colIndices = prob->hcol_ ; presolvehlink *rlink = prob->rlink_ ; CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; double *colCoeffs = prob->colels_ ; int *rowIndices = prob->hrow_ ; presolvehlink *clink = prob->clink_ ; /* Row bounds and activity, objective. */ double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *acts = prob->acts_ ; double *cost = prob->cost_ ; const double tol = prob->feasibilityTolerance_ ; action *actions = new action [ncols] ; # ifdef ZEROFAULT CoinZeroN(reinterpret_cast<char *>(actions),ncols*sizeof(action)) ; # endif int nactions = 0 ; /* This array is used to hold the indices of columns involved in substitutions, where we have the potential for cancellation. At the end they'll be checked to eliminate any actual zeros that may result. At the end of processing of each target row, the column indices of the target row are copied into zerocols. NOTE that usefulColumnInt_ is already in use for parameters implied_free and whichFree when this routine is called from implied_free. */ int *zerocols = new int[ncols] ; int nzerocols = 0 ; int *x_to_y = new int[ncols] ; int *rowsUsed = &prob->usefulRowInt_[0] ; int nRowsUsed = 0 ; /* Open a loop to process the (equality r, implied free variable t) pairs in whichFree and implied_free. It can happen that removal of (row, natural singleton) pairs back in implied_free will reduce the length of column t. It can also happen that previous processing here has resulted in fillin or cancellation. So check again for column length and exclude natural singletons and overly dense columns. */ for (int iLook = 0 ; iLook < numberFree ; iLook++) { const int tgtcol = whichFree[iLook] ; const int tgtcol_len = colLengths[tgtcol] ; const int tgtrow = implied_free[iLook] ; const int tgtrow_len = rowLengths[tgtrow] ; assert(fabs(rlo[tgtrow]-rup[tgtrow]) < tol) ; if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); length now " << colLengths[tgtcol] << "." << std::endl ; # endif continue ; } CoinBigIndex tgtcs = colStarts[tgtcol] ; CoinBigIndex tgtce = tgtcs+colLengths[tgtcol] ; /* A few checks to make sure that the candidate pair is still suitable. Processing candidates earlier in the list can eliminate coefficients. * Don't use this pair if any involved row i has become a row singleton or empty. * Don't use this pair if any involved row has been modified as part of the processing for a previous candidate pair on this call. * Don't use this pair if a(i,tgtcol) has become zero. The checks on a(i,tgtcol) seem superfluous but it's possible that implied_free identified two candidate pairs to eliminate the same column. If we've already processed one of them, we could be in trouble. */ double tgtcoeff = 0.0 ; bool dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; if (rowLengths[i] < 2 || prob->rowUsed(i)) { dealBreaker = true ; break ; } const double aij = colCoeffs[kcol] ; if (fabs(aij) <= ZTOLDP2) { dealBreaker = true ; break ; } if (i == tgtrow) tgtcoeff = aij ; } if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (1)." << std::endl ; # endif continue ; } /* Check for numerical stability.A large coeff_factor will inflate the coefficients in the substitution formula. */ dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const double coeff_factor = fabs(colCoeffs[kcol]/tgtcoeff) ; if (coeff_factor > 10.0) dealBreaker = true ; } /* Given enough target rows with sufficient overlap, there's an outside chance we could overflow zerocols. Unlikely to ever happen. */ if (!dealBreaker && nzerocols+rowLengths[tgtrow] >= ncols) dealBreaker = true ; if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (2)." << std::endl ; # endif continue ; } /* If c(t) != 0, we will need to modify the objective coefficients and remember the original objective. */ const bool nonzero_cost = (fabs(cost[tgtcol]) > tol) ; double *costsx = (nonzero_cost?new double[rowLengths[tgtrow]]:0) ; # if PRESOLVE_DEBUG > 1 std::cout << " Eliminating row " << tgtrow << ", col " << tgtcol ; if (nonzero_cost) std::cout << ", cost " << cost[tgtcol] ; std::cout << "." << std::endl ; # endif /* Count up the total number of coefficients in entangled rows and mark them as contaminated. */ int ntotels = 0 ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; ntotels += rowLengths[i] ; PRESOLVEASSERT(!prob->rowUsed(i)) ; prob->setRowUsed(i) ; rowsUsed[nRowsUsed++] = i ; } /* Create the postsolve object. Copy in all the affected rows. Take the opportunity to mark the entangled rows as changed and put them on the list of rows to process in the next round. coeffxs in particular holds the coefficients of the target column. */ action *ap = &actions[nactions++] ; ap->col = tgtcol ; ap->rowy = tgtrow ; PRESOLVE_DETAIL_PRINT(printf("pre_subst %dC %dR E\n",tgtcol,tgtrow)) ; ap->nincol = tgtcol_len ; ap->rows = new int[tgtcol_len] ; ap->rlos = new double[tgtcol_len] ; ap->rups = new double[tgtcol_len] ; ap->costsx = costsx ; ap->coeffxs = new double[tgtcol_len] ; ap->ninrowxs = new int[tgtcol_len] ; ap->rowcolsxs = new int[ntotels] ; ap->rowelsxs = new double[ntotels] ; ntotels = 0 ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int ndx = kcol-tgtcs ; const int i = rowIndices[kcol] ; const CoinBigIndex krs = rowStarts[i] ; prob->addRow(i) ; ap->rows[ndx] = i ; ap->ninrowxs[ndx] = rowLengths[i] ; ap->rlos[ndx] = rlo[i] ; ap->rups[ndx] = rup[i] ; ap->coeffxs[ndx] = colCoeffs[kcol] ; CoinMemcpyN(&colIndices[krs],rowLengths[i],&ap->rowcolsxs[ntotels]) ; CoinMemcpyN(&rowCoeffs[krs],rowLengths[i],&ap->rowelsxs[ntotels]) ; ntotels += rowLengths[i] ; } CoinBigIndex tgtrs = rowStarts[tgtrow] ; CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ; /* Adjust the objective coefficients based on the substitution formula c'(j) = c(j) - a(rj)c(t)/a(rt) */ if (nonzero_cost) { const double tgtcost = cost[tgtcol] ; for (CoinBigIndex krow = tgtrs ; krow < tgtre ; krow ++) { const int j = colIndices[krow] ; prob->addCol(j) ; costsx[krow-tgtrs] = cost[j] ; double coeff = rowCoeffs[krow] ; cost[j] -= (tgtcost*coeff)/tgtcoeff ; } prob->change_bias(tgtcost*rlo[tgtrow]/tgtcoeff) ; cost[tgtcol] = 0.0 ; } # if PRESOLVE_DEBUG > 1 std::cout << " tgt (" << tgtrow << ") (" << tgtrow_len << "): " ; for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) { const int j = colIndices[krow] ; const double arj = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << arj << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif // kill small if wanted int relax= (prob->presolveOptions()&0x60000)>>17; double tolerance = 1.0e-12; for (int i=0;i<relax;i++) tolerance *= 10.0; /* Sort the target row for efficiency when doing elimination. */ CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ; /* Get down to the business of substituting for tgtcol in the entangled rows. Open a loop to walk the target column. We walk the saved column because the bulk store can change as we work. We don't want to repeat or miss a row. */ for (int colndx = 0 ; colndx < tgtcol_len ; ++colndx) { int i = ap->rows[colndx] ; if (i == tgtrow) continue ; double ait = ap->coeffxs[colndx] ; double coeff_factor = -ait/tgtcoeff ; CoinBigIndex krs = rowStarts[i] ; CoinBigIndex kre = krs+rowLengths[i] ; # if PRESOLVE_DEBUG > 1 std::cout << " subst pre (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif /* Sort the row for efficiency and call add_row to do the actual business of changing coefficients due to substitution. This has the potential to trigger compaction of the row-major bulk store, so update bulk store indices. */ CoinSort_2(colIndices+krs,colIndices+kre,rowCoeffs+krs) ; bool outOfSpace = add_row(rowStarts,rlo,acts,rup,rowCoeffs,colIndices, rowLengths,rlink,nrows,coeff_factor,tolerance,i,tgtrow, x_to_y) ; if (outOfSpace) throwCoinError("out of memory","CoinImpliedFree::presolve") ; krs = rowStarts[i] ; kre = krs+rowLengths[i] ; tgtrs = rowStarts[tgtrow] ; tgtre = tgtrs+rowLengths[tgtrow] ; # if PRESOLVE_DEBUG > 1 std::cout << " subst aft (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif /* Now update the column-major representation from the row-major representation. This is easy if the coefficient already exists, but painful if there's fillin. presolve_find_row1 will return the index of the row in the column vector, or one past the end if it's missing. If the coefficient is fill, presolve_expand_col will make sure that there's room in the column for one more coefficient. This may require that the column be moved in the bulk store, so we need to update kcs and kce. Once we're done, a(it) = 0 (i.e., we've eliminated x(t) from row i). Physically remove the explicit zero from the row-major representation with presolve_delete_from_row. */ for (CoinBigIndex rowndx = 0 ; rowndx < tgtrow_len ; ++rowndx) { const CoinBigIndex ktgt = tgtrs+rowndx ; const int j = colIndices[ktgt] ; CoinBigIndex kcs = colStarts[j] ; CoinBigIndex kce = kcs+colLengths[j] ; assert(colIndices[krs+x_to_y[rowndx]] == j) ; const double coeff = rowCoeffs[krs+x_to_y[rowndx]] ; CoinBigIndex kcol = presolve_find_row1(i,kcs,kce,rowIndices) ; if (kcol < kce) { colCoeffs[kcol] = coeff ; } else { outOfSpace = presolve_expand_col(colStarts,colCoeffs,rowIndices, colLengths,clink,ncols,j) ; if (outOfSpace) throwCoinError("out of memory","CoinImpliedFree::presolve") ; kcs = colStarts[j] ; kce = kcs+colLengths[j] ; rowIndices[kce] = i ; colCoeffs[kce] = coeff ; colLengths[j]++ ; } } presolve_delete_from_row(i,tgtcol, rowStarts,rowLengths,colIndices,rowCoeffs) ; # if PRESOLVE_DEBUG > 1 kre-- ; std::cout << " subst fin (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif } /* End of the substitution loop. Record the column indices of the target row so we can groom these columns later to remove possible explicit zeros. */ CoinMemcpyN(&colIndices[rowStarts[tgtrow]],rowLengths[tgtrow], &zerocols[nzerocols]) ; nzerocols += rowLengths[tgtrow] ; /* Remove the target equality from the column- and row-major representations Somewhat painful in the colum-major representation. We have to walk the target row in the row-major representation and look up each coefficient in the column-major representation. */ for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) { const int j = colIndices[krow] ; # if PRESOLVE_DEBUG > 1 std::cout << " removing row " << tgtrow << " from col " << j << std::endl ; # endif presolve_delete_from_col(tgtrow,j, colStarts,colLengths,rowIndices,colCoeffs) ; if (colLengths[j] == 0) { PRESOLVE_REMOVE_LINK(clink,j) ; } } /* Finally, physically remove the column from the column-major representation and the row from the row-major representation. */ PRESOLVE_REMOVE_LINK(clink, tgtcol) ; colLengths[tgtcol] = 0 ; PRESOLVE_REMOVE_LINK(rlink, tgtrow) ; rowLengths[tgtrow] = 0 ; rlo[tgtrow] = 0.0 ; rup[tgtrow] = 0.0 ; # if PRESOLVE_CONSISTENCY > 0 presolve_links_ok(prob) ; presolve_consistent(prob) ; # endif } /* That's it, we've processed all the candidate pairs. Clear the row used flags. */ for (int i = 0 ; i < nRowsUsed ; i++) prob->unsetRowUsed(rowsUsed[i]) ; /* Trim the array of substitution transforms and queue up objects for postsolve. Also groom the problem representation to remove explicit zeros. */ if (nactions) { # if PRESOLVE_SUMMARY > 0 std::cout << "NSUBSTS: " << nactions << std::endl ; # endif next = new subst_constraint_action(nactions, CoinCopyOfArray(actions,nactions),next) ; next = drop_zero_coefficients_action::presolve(prob,zerocols, nzerocols, next) ; # if PRESOLVE_CONSISTENCY > 0 presolve_links_ok(prob) ; presolve_consistent(prob) ; # endif } deleteAction(actions,action*) ; delete [] x_to_y ; delete [] zerocols ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_sol(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving subst_constraint_action::presolve, " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
/* * It is always the case that one of the variables of a doubleton * will be (implied) free, but neither will necessarily be a singleton. * Since in the case of a doubleton the number of non-zero entries * will never increase, though, it makes sense to always eliminate them. * * The col rep and row rep must be consistent. */ const CoinPresolveAction *doubleton_action::presolve (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double startTime = 0.0; int startEmptyRows=0; int startEmptyColumns = 0; if (prob->tuning_) { startTime = CoinCpuTime(); startEmptyRows = prob->countEmptyRows(); startEmptyColumns = prob->countEmptyCols(); } double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int ncols = prob->ncols_; double *clo = prob->clo_; double *cup = prob->cup_; double *rowels = prob->rowels_; int *hcol = prob->hcol_; CoinBigIndex *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; int nrows = prob->nrows_; double *rlo = prob->rlo_; double *rup = prob->rup_; presolvehlink *clink = prob->clink_; presolvehlink *rlink = prob->rlink_; const unsigned char *integerType = prob->integerType_; double *cost = prob->cost_; int numberLook = prob->numberRowsToDo_; int iLook; int * look = prob->rowsToDo_; const double ztolzb = prob->ztolzb_; action * actions = new action [nrows]; int nactions = 0; int *zeros = prob->usefulColumnInt_; //new int[ncols]; int nzeros = 0; int *fixed = zeros+ncols; //new int[ncols]; int nfixed = 0; unsigned char *rowstat = prob->rowstat_; double *acts = prob->acts_; double * sol = prob->sol_; bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; # if PRESOLVE_CONSISTENCY presolve_consistent(prob) ; presolve_links_ok(prob) ; # endif // wasfor (int irow=0; irow<nrows; irow++) for (iLook=0;iLook<numberLook;iLook++) { int irow = look[iLook]; if (hinrow[irow] == 2 && fabs(rup[irow] - rlo[irow]) <= ZTOLDP) { double rhs = rlo[irow]; CoinBigIndex krs = mrstrt[irow]; int icolx, icoly; CoinBigIndex k; icolx = hcol[krs]; icoly = hcol[krs+1]; if (hincol[icolx]<=0||hincol[icoly]<=0) { // should never happen ? //printf("JJF - doubleton column %d has %d entries and %d has %d\n", // icolx,hincol[icolx],icoly,hincol[icoly]); continue; } // check size if (fabs(rowels[krs]) < ZTOLDP2 || fabs(rowels[krs+1]) < ZTOLDP2) continue; // See if prohibited for any reason if (prob->colProhibited(icolx) || prob->colProhibited(icolx)) continue; // don't bother with fixed variables if (!(fabs(cup[icolx] - clo[icolx]) < ZTOLDP) && !(fabs(cup[icoly] - clo[icoly]) < ZTOLDP)) { double coeffx, coeffy; /* find this row in each of the columns */ CoinBigIndex krowx = presolve_find_row(irow, mcstrt[icolx], mcstrt[icolx] + hincol[icolx], hrow); CoinBigIndex krowy = presolve_find_row(irow, mcstrt[icoly], mcstrt[icoly] + hincol[icoly], hrow); /* Check for integrality: If one variable is integer, keep it and substitute for the continuous variable. If both are integer, substitute only for the forms x = k * y (k integral and non-empty intersection on bounds on x) or x = 1-y, where both x and y are binary. flag bits for integerStatus: 1>>0 x integer 1>>1 y integer */ int integerStatus=0; if (integerType[icolx]) { if (integerType[icoly]) { // both integer int good = 0; double rhs2 = rhs; double value; value=colels[krowx]; if (value<0.0) { value = - value; rhs2 += 1; } if (cup[icolx]==1.0&&clo[icolx]==0.0&&fabs(value-1.0)<1.0e-7) good =1; value=colels[krowy]; if (value<0.0) { value = - value; rhs2 += 1; } if (cup[icoly]==1.0&&clo[icoly]==0.0&&fabs(value-1.0)<1.0e-7) good |= 2; if (good==3&&fabs(rhs2-1.0)<1.0e-7) integerStatus = 3; else integerStatus=-1; if (integerStatus==-1&&!rhs) { // maybe x = k * y; double value1 = colels[krowx]; double value2 = colels[krowy]; double ratio; bool swap=false; if (fabs(value1)>fabs(value2)) { ratio = value1/value2; } else { ratio = value2/value1; swap=true; } ratio=fabs(ratio); if (fabs(ratio-floor(ratio+0.5))<1.0e-12) { // possible integerStatus = swap ? 2 : 1; //printf("poss type %d\n",integerStatus); } } } else { integerStatus = 1; } } else if (integerType[icoly]) { integerStatus = 2; } if (integerStatus<0) { // can still take in some cases bool canDo=false; double value1 = colels[krowx]; double value2 = colels[krowy]; double ratio; bool swap=false; double rhsRatio; if (fabs(value1)>fabs(value2)) { ratio = value1/value2; rhsRatio = rhs/value1; } else { ratio = value2/value1; rhsRatio = rhs/value2; swap=true; } ratio=fabs(ratio); if (fabs(ratio-floor(ratio+0.5))<1.0e-12) { // possible integerStatus = swap ? 2 : 1; // but check rhs if (rhsRatio==floor(rhsRatio+0.5)) canDo=true; } #ifdef COIN_DEVELOP2 if (canDo) printf("Good CoinPresolveDoubleton icolx %d (%g and bounds %g %g) icoly %d (%g and bound %g %g) - rhs %g\n", icolx,colels[krowx],clo[icolx],cup[icolx], icoly,colels[krowy],clo[icoly],cup[icoly],rhs); else printf("Bad CoinPresolveDoubleton icolx %d (%g) icoly %d (%g) - rhs %g\n", icolx,colels[krowx],icoly,colels[krowy],rhs); #endif if (!canDo) continue; } if (integerStatus == 2) { CoinSwap(icoly,icolx); CoinSwap(krowy,krowx); } // HAVE TO JIB WITH ABOVE swapS // if x's coefficient is something like 1000, but y's only something like -1, // then when we postsolve, if x's is close to being out of tolerance, // then y is very likely to be (because y==1000x) . (55) // It it interesting that the number of doubletons found may depend // on which column is substituted away (this is true of baxter.mps). if (!integerStatus) { if (fabs(colels[krowy]) < fabs(colels[krowx])) { CoinSwap(icoly,icolx); CoinSwap(krowy,krowx); } } #if 0 //????? if (integerType[icolx] && clo[icoly] != -PRESOLVE_INF && cup[icoly] != PRESOLVE_INF) { continue; } #endif { CoinBigIndex kcs = mcstrt[icoly]; CoinBigIndex kce = kcs + hincol[icoly]; for (k=kcs; k<kce; k++) { if (hinrow[hrow[k]] == 1) { break; } } // let singleton rows be taken care of first if (k<kce) continue; } coeffx = colels[krowx]; coeffy = colels[krowy]; // it is possible that both x and y are singleton columns // that can cause problems if (hincol[icolx] == 1 && hincol[icoly] == 1) continue; // BE CAUTIOUS and avoid very large relative differences // if this is not done in baxter, then the computed solution isn't optimal, // but gets it in 11995 iterations; the postsolve goes to iteration 16181. // with this, the solution is optimal, but takes 18825 iters; postsolve 18871. #if 0 if (fabs(coeffx) * max_coeff_factor <= fabs(coeffy)) continue; #endif #if 0 if (only_zero_rhs && rhs != 0) continue; if (reject_doubleton(mcstrt, colels, hrow, hincol, -coeffx / coeffy, max_coeff_ratio, irow, icolx, icoly)) continue; #endif // common equations are of the form ax + by = 0, or x + y >= lo { PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n", icoly,icolx,irow)); action *s = &actions[nactions]; nactions++; s->row = irow; s->icolx = icolx; s->clox = clo[icolx]; s->cupx = cup[icolx]; s->costx = cost[icolx]; s->icoly = icoly; s->costy = cost[icoly]; s->rlo = rlo[irow]; s->coeffx = coeffx; s->coeffy = coeffy; s->ncolx = hincol[icolx]; s->ncoly = hincol[icoly]; if (s->ncoly<s->ncolx) { // Take out row s->colel = presolve_dupmajor(colels,hrow,hincol[icoly], mcstrt[icoly],irow) ; s->ncolx=0; } else { s->colel = presolve_dupmajor(colels,hrow,hincol[icolx], mcstrt[icolx],irow) ; s->ncoly=0; } } /* * This moves the bounds information for y onto x, * making y free and allowing us to substitute it away. * * a x + b y = c * l1 <= x <= u1 * l2 <= y <= u2 ==> * * l2 <= (c - a x) / b <= u2 * b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a * b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a */ { double lo1 = -PRESOLVE_INF; double up1 = PRESOLVE_INF; //PRESOLVEASSERT((coeffx < 0) == (coeffy/-coeffx < 0)); // (coeffy/-coeffx < 0) == (coeffy<0 == coeffx<0) if (-PRESOLVE_INF < clo[icoly]) { if (coeffx * coeffy < 0) lo1 = (coeffy * clo[icoly] - rhs) / -coeffx; else up1 = (coeffy * clo[icoly] - rhs) / -coeffx; } if (cup[icoly] < PRESOLVE_INF) { if (coeffx * coeffy < 0) up1 = (coeffy * cup[icoly] - rhs) / -coeffx; else lo1 = (coeffy * cup[icoly] - rhs) / -coeffx; } // costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b // the effect of maxmin cancels out cost[icolx] += cost[icoly] * (-coeffx / coeffy); prob->change_bias(cost[icoly] * rhs / coeffy); if (0 /*integerType[icolx]*/) { abort(); /* no change possible for now */ #if 0 lo1 = trunc(lo1); up1 = trunc(up1); /* trunc(3.5) == 3.0 */ /* trunc(-3.5) == -3.0 */ /* I think this is ok */ if (lo1 > clo[icolx]) { (clo[icolx] <= 0.0) clo[icolx] = ? ilo clo[icolx] = ilo; cup[icolx] = iup; } #endif } else {
const CoinPresolveAction *forcing_constraint_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double startTime = 0.0; int startEmptyRows=0; int startEmptyColumns = 0; if (prob->tuning_) { startTime = CoinCpuTime(); startEmptyRows = prob->countEmptyRows(); startEmptyColumns = prob->countEmptyCols(); } double *clo = prob->clo_; double *cup = prob->cup_; double *csol = prob->sol_ ; const double *rowels = prob->rowels_; const int *hcol = prob->hcol_; const CoinBigIndex *mrstrt = prob->mrstrt_; const int *hinrow = prob->hinrow_; const int nrows = prob->nrows_; const double *rlo = prob->rlo_; const double *rup = prob->rup_; // const char *integerType = prob->integerType_; const double tol = ZTOLDP; const double inftol = prob->feasibilityTolerance_; const int ncols = prob->ncols_; int *fixed_cols = new int[ncols]; int nfixed_cols = 0; action *actions = new action [nrows]; int nactions = 0; int *useless_rows = new int[nrows]; int nuseless_rows = 0; int numberLook = prob->numberRowsToDo_; int iLook; int * look = prob->rowsToDo_; bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; # if PRESOLVE_DEBUG std::cout << "Entering forcing_constraint_action::presolve." << std::endl ; presolve_check_sol(prob) ; # endif /* Open a loop to scan the constraints of interest. There must be variables left in the row. */ for (iLook=0;iLook<numberLook;iLook++) { int irow = look[iLook]; if (hinrow[irow] > 0) { CoinBigIndex krs = mrstrt[irow]; CoinBigIndex kre = krs + hinrow[irow]; /* Calculate upper and lower bounds on the row activity based on upper and lower bounds on the variables. If these are finite and incompatible with the given row bounds, we have infeasibility. */ double maxup, maxdown; implied_row_bounds(rowels, clo, cup, hcol, krs, kre, &maxup, &maxdown); if (maxup < PRESOLVE_INF && maxup + inftol < rlo[irow]&&!fixInfeasibility) { /* max row activity below the row lower bound */ prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) <<irow <<rlo[irow] <<rup[irow] <<CoinMessageEol; break; } else if (-PRESOLVE_INF < maxdown && rup[irow] < maxdown - inftol&&!fixInfeasibility) { /* min row activity above the row upper bound */ prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) <<irow <<rlo[irow] <<rup[irow] <<CoinMessageEol; break; } // ADD TOLERANCE TO THESE TESTS else if ((rlo[irow] <= -PRESOLVE_INF || (-PRESOLVE_INF < maxdown && rlo[irow] <= maxdown)) && (rup[irow] >= PRESOLVE_INF || (maxup < PRESOLVE_INF && rup[irow] >= maxup))) { /* Original comment: I'm not sure that these transforms don't intefere with each other. We can get it next time. Well, I'll argue that bounds are never really loosened (at worst, they're transferred onto some other variable, or inferred to be unnecessary. Once useless, always useless. Leaving this hook in place allows for a sort of infinite loop where this routine keeps queuing the same constraints over and over. -- lh, 040901 -- if (some_col_was_fixed(hcol, krs, kre, clo, cup)) { prob->addRow(irow); continue; } */ // this constraint must always be satisfied - drop it useless_rows[nuseless_rows++] = irow; } else if ((maxup < PRESOLVE_INF && fabs(rlo[irow] - maxup) < tol) || (-PRESOLVE_INF < maxdown && fabs(rup[irow] - maxdown) < tol)) { // the lower bound can just be reached, or // the upper bound can just be reached; // called a "forcing constraint" in the paper (p. 226) const int lbound_tight = (maxup < PRESOLVE_INF && fabs(rlo[irow] - maxup) < tol); /* Original comment and rebuttal as above. if (some_col_was_fixed(hcol, krs, kre, clo, cup)) { // make sure on next time prob->addRow(irow); continue; } */ // out of space - this probably never happens (but this routine will // often put duplicates in the fixed column list) if (nfixed_cols + (kre-krs) >= ncols) break; double *bounds = new double[hinrow[irow]]; int *rowcols = new int[hinrow[irow]]; int lk = krs; // load fix-to-down in front int uk = kre; // load fix-to-up in back CoinBigIndex k; for ( k=krs; k<kre; k++) { int jcol = hcol[k]; prob->addCol(jcol); double coeff = rowels[k]; PRESOLVEASSERT(fabs(coeff) > ZTOLDP); // one of the two contributed to maxup - set the other to that if (lbound_tight == (coeff > 0.0)) { --uk; bounds[uk-krs] = clo[jcol]; rowcols[uk-krs] = jcol; if (csol != 0) { csol[jcol] = cup[jcol] ; } clo[jcol] = cup[jcol]; } else { bounds[lk-krs] = cup[jcol]; rowcols[lk-krs] = jcol; ++lk; if (csol != 0) { csol[jcol] = clo[jcol] ; } cup[jcol] = clo[jcol]; } fixed_cols[nfixed_cols++] = jcol; } PRESOLVEASSERT(uk == lk); action *f = &actions[nactions]; nactions++; PRESOLVE_DETAIL_PRINT(printf("pre_forcing %dR E\n",irow)); f->row = irow; f->nlo = lk-krs; f->nup = kre-uk; f->rowcols = rowcols; f->bounds = bounds; } } } if (nactions) { #if PRESOLVE_SUMMARY printf("NFORCED: %d\n", nactions); #endif next = new forcing_constraint_action(nactions, CoinCopyOfArray(actions,nactions), next); } deleteAction(actions,action*); if (nuseless_rows) { next = useless_constraint_action::presolve(prob, useless_rows, nuseless_rows, next); } delete[]useless_rows; /* We need to remove duplicates here, or we get into trouble in remove_fixed_action::postsolve when we try to reinstate a column multiple times. */ if (nfixed_cols) { if (nfixed_cols > 1) { std::sort(fixed_cols,fixed_cols+nfixed_cols) ; int *end = std::unique(fixed_cols,fixed_cols+nfixed_cols) ; nfixed_cols = static_cast<int>(end-fixed_cols) ; } next = remove_fixed_action::presolve(prob,fixed_cols,nfixed_cols,next) ; } delete[]fixed_cols ; if (prob->tuning_) { double thisTime=CoinCpuTime(); int droppedRows = prob->countEmptyRows() - startEmptyRows ; int droppedColumns = prob->countEmptyCols() - startEmptyColumns; printf("CoinPresolveForcing(32) - %d rows, %d columns dropped in time %g, total %g\n", droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); } # if PRESOLVE_DEBUG presolve_check_sol(prob) ; std::cout << "Leaving forcing_constraint_action::presolve." << std::endl ; # endif return (next); }