int pushCbcOsiLogLevel (CoinParam *param) { assert (param != 0) ; CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ; assert (osiParam != 0) ; OsiSolverInterface *osi = osiParam->obj() ; assert(osi != 0) ; int lvl = param->intVal() ; /* Setup to return nonfatal/fatal error (1/-1) by default, so that all we need to do is correct to 0 (no error) if we're successful. */ int retval ; if (CoinParamUtils::isInteractive()) { retval = 1 ; } else { retval = -1 ; } /* Now try to do the right thing with a hint. Harder to say -- assume that log level 1 is `normal'. */ OsiHintStrength strength ; bool sense ; if (lvl < 1) { strength = OsiHintDo ; sense = true ; } else if (lvl == 1) { strength = OsiHintIgnore ; sense = true ; } else if (lvl == 2) { strength = OsiHintTry ; sense = false ; } else { strength = OsiHintDo ; sense = false ; } bool setOK = osi->setHintParam(OsiDoReducePrint, sense, strength) ; /* Recover the message handler and set the log level directly. */ CoinMessageHandler *hndl = osi->messageHandler() ; assert (hndl != 0) ; hndl->setLogLevel(lvl) ; if (setOK) { return (0) ; } else { return (retval) ; } }
/* Original comments from 040916: This routine looks to be something of a work in progress. 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. l<j> = -infty is uncommon; perhaps it's not worth the effort? Why exclude the code protected by PRESOLVE_TIGHTEN_DUALS? Why are we using ekkinf instead of PRESOLVE_INF? */ const CoinPresolveAction *remove_dual_action::presolve (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { # if PRESOLVE_DEBUG > 0 std::cout << "Entering remove_dual_action::presolve, " << prob->nrows_ << "x" << prob->ncols_ << "." << std::endl ; # endif # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_sol(prob,2,1,1) ; 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 // column-major representation const int ncols = prob->ncols_ ; const CoinBigIndex *const mcstrt = prob->mcstrt_ ; const int *const hincol = prob->hincol_ ; const int *const hrow = prob->hrow_ ; const double *const colels = prob->colels_ ; const double *const cost = prob->cost_ ; // column type, bounds, solution, and status const unsigned char *const integerType = prob->integerType_ ; const double *const clo = prob->clo_ ; const double *const cup = prob->cup_ ; double *const csol = prob->sol_ ; unsigned char *&colstat = prob->colstat_ ; // row-major representation const int nrows = prob->nrows_ ; const CoinBigIndex *const mrstrt = prob->mrstrt_ ; const int *const hinrow = prob->hinrow_ ; const int *const hcol = prob->hcol_ ; # if REMOVE_DUAL_ACTION_REPAIR_SOLN > 0 const double *const rowels = prob->rowels_ ; # endif // row bounds double *const rlo = prob->rlo_ ; double *const rup = prob->rup_ ; // tolerances const double ekkinf2 = PRESOLVE_SMALL_INF ; const double ekkinf = ekkinf2*1.0e8 ; const double ztolcbarj = prob->ztoldj_ ; const CoinRelFltEq relEq(prob->ztolzb_) ; /* Grab one of the preallocated scratch arrays to hold min and max values of row duals. */ double *ymin = prob->usefulRowDouble_ ; double *ymax = ymin+nrows ; /* Initialise row dual min/max. The defaults are +/- infty, but if we know that the logical has no upper (lower) bound, it can only be nonbasic at the other bound. Given minimisation, we can conclude: * <= constraint ==> [0,infty] ==> NBLB ==> cbar<i> > 0 ==> y<i> < 0 * >= constraint ==> [-infty,0] ==> NBUB ==> cbar<i> < 0 ==> y<i> > 0 Range constraints are not helpful here, the dual can be either sign. There's no calculation because we assume the objective coefficient c<i> = 0 and the coefficient a<ii> = 1.0, hence cbar<i> = -y<i>. */ for (int i = 0; i < nrows; i++) { const bool no_lb = (rup[i] >= ekkinf) ; const bool no_ub = (rlo[i] <= -ekkinf) ; ymin[i] = ((no_lb && !no_ub)?0.0:(-PRESOLVE_INF)) ; ymax[i] = ((no_ub && !no_lb)?0.0:PRESOLVE_INF) ; } /* We can do a similar calculation with singleton columns where the variable has only one finite bound, but we have to work a bit harder, as the cost coefficient c<j> is not necessarily 0.0 and a<ij> is not necessarily 1.0. cbar<j> = c<j> - y<i>a<ij>, hence y<i> = c<j>/a<ij> at cbar<j> = 0. The question is whether this is an upper or lower bound on y<i>. * x<j> NBLB ==> cbar<j> >= 0 a<ij> > 0 ==> increasing y<i> decreases cbar<j> ==> upper bound a<ij> < 0 ==> increasing y<i> increases cbar<j> ==> lower bound * x<j> NBUB ==> cbar<j> <= 0 a<ij> > 0 ==> increasing y<i> decreases cbar<j> ==> lower bound a<ij> < 0 ==> increasing y<i> increases cbar<j> ==> upper bound The condition below (simple test for equality to choose the bound) looks a bit odd, but a bit of boolean algebra should convince you it's correct. We have a bound; the only question is whether it's upper or lower. Skip integer variables; it's far too likely that we'll tighten infinite bounds elsewhere in presolve. NOTE: If bound propagation is applied to continuous variables, the same hazard will apply. -- lh, 110611 -- */ for (int j = 0 ; j < ncols ; j++) { if (integerType[j]) continue ; if (hincol[j] != 1) continue ; const bool no_ub = (cup[j] >= ekkinf) ; const bool no_lb = (clo[j] <= -ekkinf) ; if (no_ub != no_lb) { const int &i = hrow[mcstrt[j]] ; double aij = colels[mcstrt[j]] ; PRESOLVEASSERT(fabs(aij) > ZTOLDP) ; const double yzero = cost[j]/aij ; if ((aij > 0.0) == no_ub) { if (ymax[i] > yzero) ymax[i] = yzero ; } else { if (ymin[i] < yzero) ymin[i] = yzero ; } } } int nfixup_cols = 0 ; int nfixdown_cols = ncols ; // Grab another work array, sized to ncols_ int *fix_cols = prob->usefulColumnInt_ ; # if PRESOLVE_TIGHTEN_DUALS > 0 double *cbarmin = new double[ncols] ; double *cbarmax = new double[ncols] ; # endif /* Now we have (admittedly weak) bounds on the dual for each row. We can use these to calculate upper and lower bounds on cbar<j>. Open loops to take multiple passes over all columns. */ int nPass = 0 ; while (nPass++ < 100) { int tightened = 0 ; for (int j = 0 ; j < ncols ; j++) { if (hincol[j] <= 0) continue ; /* Calculate min cbar<j> and max cbar<j> for the column by calculating the contribution to c<j>-ya<j> using ymin<i> and ymax<i> from above. */ const CoinBigIndex &kcs = mcstrt[j] ; const 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 cbarjmin = cost[j] ; double cbarjmax = cbarjmin ; for (CoinBigIndex k = kcs ; k < kce ; k++) { const int &i = hrow[k] ; const double &aij = colels[k] ; const double mindelta = aij*ymin[i] ; const double maxdelta = aij*ymax[i] ; if (aij > 0.0) { if (ymin[i] >= -ekkinf2) { cbarjmax -= mindelta ; nordu++ ; } else { nflagu++ ; } if (ymax[i] <= ekkinf2) { cbarjmin -= maxdelta ; nordl++ ; } else { nflagl++ ; } } else { if (ymax[i] <= ekkinf2) { cbarjmax -= maxdelta ; nordu++ ; } else { nflagu++ ; } if (ymin[i] >= -ekkinf2) { cbarjmin -= mindelta ; nordl++ ; } else { nflagl++ ; } } } /* See if we can tighten bounds on a dual y<t>. See the comments at the head of the file for the linear algebra. At this point, I don't understand the restrictions on propagation. Neither are necessary. The net effect is to severely restrict the circumstances where we'll propagate. Requiring nflagu == 1 excludes the case where all duals have finite bounds (unlikely?). And why cbarjmax < -ztolcbarj? In any event, we're looking for the row that's contributing the infinity. If a<tj> > 0, the contribution is due to ymin<t> and we tighten ymax<t>; a<tj> < 0, ymax<t> and ymin<t>, respectively. The requirement cbarjmax < (ymax[i]*aij-ztolcbarj) ensures we don't propagate tiny changes. If we make a change, it will affect cbarjmin. Make the adjustment immediately. Continuous variables only. */ if (!integerType[j]) { if (cup[j] > ekkinf) { if (nflagu == 1 && cbarjmax < -ztolcbarj) { for (CoinBigIndex k = kcs ; k < kce; k++) { const int i = hrow[k] ; const double aij = colels[k] ; if (aij > 0.0 && ymin[i] < -ekkinf2) { if (cbarjmax < (ymax[i]*aij-ztolcbarj)) { const double newValue = cbarjmax/aij ; if (ymax[i] > ekkinf2 && newValue <= ekkinf2) { nflagl-- ; cbarjmin -= aij*newValue ; } else if (ymax[i] <= ekkinf2) { cbarjmin -= aij*(newValue-ymax[i]) ; } # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(infu/inf): u(" << j << ") = " << cup[j] << ": max y(" << i << ") was " << ymax[i] << " now " << newValue << "." << std::endl ; # endif ymax[i] = newValue ; tightened++ ; } } else if (aij < 0.0 && ymax[i] > ekkinf2) { if (cbarjmax < (ymin[i]*aij-ztolcbarj)) { const double newValue = cbarjmax/aij ; if (ymin[i] < -ekkinf2 && newValue >= -ekkinf2) { nflagl-- ; cbarjmin -= aij*newValue ; } else if (ymin[i] >= -ekkinf2) { cbarjmin -= aij*(newValue-ymin[i]) ; } # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(infu/inf): u(" << j << ") = " << cup[j] << ": min y(" << i << ") was " << ymin[i] << " now " << newValue << "." << std::endl ; # endif ymin[i] = newValue ; tightened++ ; // Huh? asymmetric // cbarjmin = 0.0 ; } } } } else if (nflagl == 0 && nordl == 1 && cbarjmin < -ztolcbarj) { /* This is a column singleton. Why are we doing this? It's not like changes to other y will affect this. */ for (CoinBigIndex k = kcs; k < kce; k++) { const int i = hrow[k] ; const double aij = colels[k] ; if (aij > 0.0) { # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(infu/sing): u(" << j << ") = " << cup[j] << ": max y(" << i << ") was " << ymax[i] << " now " << ymax[i]+cbarjmin/aij << "." << std::endl ; # endif ymax[i] += cbarjmin/aij ; cbarjmin = 0.0 ; tightened++ ; } else if (aij < 0.0 ) { # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(infu/sing): u(" << j << ") = " << cup[j] << ": min y(" << i << ") was " << ymin[i] << " now " << ymin[i]+cbarjmin/aij << "." << std::endl ; # endif ymin[i] += cbarjmin/aij ; cbarjmin = 0.0 ; tightened++ ; } } } } // end u<j> = infty # if PROCESS_INFINITE_LB /* Unclear why this section is commented out, except for the possibility that bounds of -infty < x < something are rare and it likely suffered fromm the same errors. Consider the likelihood that this whole block needs to be edited to sway min/max, & similar. */ if (clo[j]<-ekkinf) { // cbarj can not be positive if (cbarjmin > ztolcbarj&&nflagl == 1) { // We can make bound finite one way for (CoinBigIndex k = kcs; k < kce; k++) { const int i = hrow[k] ; const double coeff = colels[k] ; if (coeff < 0.0&&ymin[i] < -ekkinf2) { // ymax[i] has upper bound if (cbarjmin>ymax[i]*coeff+ztolcbarj) { const double newValue = cbarjmin/coeff ; // re-compute hi if (ymax[i] > ekkinf2 && newValue <= ekkinf2) { nflagu-- ; cbarjmax -= coeff * newValue ; } else if (ymax[i] <= ekkinf2) { cbarjmax -= coeff * (newValue-ymax[i]) ; } ymax[i] = newValue ; tightened++ ; # if PRESOLVE_DEBUG > 1 printf("Col %d, row %d max pi now %g\n",j,i,ymax[i]) ; # endif } } else if (coeff > 0.0 && ymax[i] > ekkinf2) { // ymin[i] has lower bound if (cbarjmin>ymin[i]*coeff+ztolcbarj) { const double newValue = cbarjmin/coeff ; // re-compute lo if (ymin[i] < -ekkinf2 && newValue >= -ekkinf2) { nflagu-- ; cbarjmax -= coeff * newValue ; } else if (ymin[i] >= -ekkinf2) { cbarjmax -= coeff*(newValue-ymin[i]) ; } ymin[i] = newValue ; tightened++ ; # if PRESOLVE_DEBUG > 1 printf("Col %d, row %d min pi now %g\n",j,i,ymin[i]) ; # endif } } } } else if (nflagu == 0 && nordu == 1 && cbarjmax > ztolcbarj) { // We may be able to tighten for (CoinBigIndex k = kcs; k < kce; k++) { const int i = hrow[k] ; const double coeff = colels[k] ; if (coeff < 0.0) { ymax[i] += cbarjmax/coeff ; cbarjmax =0.0 ; tightened++ ; # if PRESOLVE_DEBUG > 1 printf("Col %d, row %d max pi now %g\n",j,i,ymax[i]) ; # endif } else if (coeff > 0.0 ) { ymin[i] += cbarjmax/coeff ; cbarjmax =0.0 ; tightened++ ; # if PRESOLVE_DEBUG > 1 printf("Col %d, row %d min pi now %g\n",j,i,ymin[i]) ; # endif } } } } // end l<j> < -infty # endif // PROCESS_INFINITE_LB } /* That's the end of propagation of bounds for dual variables. */ # if PRESOLVE_TIGHTEN_DUALS > 0 cbarmin[j] = (nflagl?(-PRESOLVE_INF):cbarjmin) ; cbarmax[j] = (nflagu?PRESOLVE_INF:cbarjmax) ; # endif /* If cbarmin<j> > 0 (strict inequality) then x<j> NBLB at optimality. If l<j> is -infinity, notify the user and set the status to unbounded. */ if (cbarjmin > ztolcbarj && nflagl == 0 && !prob->colProhibited2(j)) { if (clo[j] <= -ekkinf) { CoinMessageHandler *msghdlr = prob->messageHandler() ; msghdlr->message(COIN_PRESOLVE_COLUMNBOUNDB,prob->messages()) << j << CoinMessageEol ; prob->status_ |= 2 ; break ; } else { fix_cols[--nfixdown_cols] = j ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(fix l): fix x(" << j << ")" ; if (csol) std::cout << " = " << csol[j] ; std::cout << " at l(" << j << ") = " << clo[j] << "; cbar(" << j << ") > " << cbarjmin << "." << std::endl ; # endif if (csol) { # if REMOVE_DUAL_ACTION_REPAIR_SOLN > 0 /* Original comment: User may have given us feasible solution - move if simple Except it's not simple. The net result is that we end up with an excess of basic variables. Mark x<j> NBLB and let the client recalculate the solution after establishing the basis. */ 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++) { const int k = hcol[kk] ; if (colstat[k] == CoinPrePostsolveMatrix::superBasic) continue ; if (hincol[k] == 1 && k != j) { const 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(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] ; colstat[j] = CoinPrePostsolveMatrix::atLowerBound ; } } } else if (cbarjmax < -ztolcbarj && nflagu == 0 && !prob->colProhibited2(j)) { /* If cbarmax<j> < 0 (strict inequality) then x<j> NBUB at optimality. If u<j> is infinity, notify the user and set the status to unbounded. */ if (cup[j] >= ekkinf) { CoinMessageHandler *msghdlr = prob->messageHandler() ; msghdlr->message(COIN_PRESOLVE_COLUMNBOUNDA,prob->messages()) << j << CoinMessageEol ; prob->status_ |= 2 ; break ; } else { fix_cols[nfixup_cols++] = j ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(fix u): fix x(" << j << ")" ; if (csol) std::cout << " = " << csol[j] ; std::cout << " at u(" << j << ") = " << cup[j] << "; cbar(" << j << ") < " << cbarjmax << "." << std::endl ; # endif if (csol) { # if 0 // See comments above for 'fix at lb'. 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++) { const int k = hcol[kk] ; if (colstat[k] == CoinPrePostsolveMatrix::superBasic) continue ; if (hincol[k] == 1 && k != j) { const 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(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] ; colstat[j] = CoinPrePostsolveMatrix::atUpperBound ; } } } // end cbar<j> < 0 } /* That's the end of this walk through the columns. */ // I don't know why I stopped doing this. # if PRESOLVE_TIGHTEN_DUALS > 0 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++) { const bool no_ub = (rup[i] >= ekkinf) ; const bool no_lb = (rlo[i] <= -ekkinf) ; if ((no_ub ^ no_lb) == true) { const CoinBigIndex krs = mrstrt[i] ; const CoinBigIndex kre = krs + hinrow[i] ; const double rmax = ymax[i] ; const double rmin = ymin[i] ; // all row columns are non-empty for (CoinBigIndex k = krs ; k < kre ; k++) { const double coeff = rowels[k] ; const int icol = hcol[k] ; const double cbarmax0 = cbarmax[icol] ; const double cbarmin0 = cbarmin[icol] ; if (no_ub) { // cbarj must not be negative if (coeff > ZTOLDP2 && cbarjmax0 < PRESOLVE_INF && cup[icol] >= ekkinf) { const double bnd = cbarjmax0 / coeff ; if (rmax > bnd) { # if PRESOLVE_DEBUG > 1 printf("MAX TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymax[i],bnd) ; # endif ymax[i] = rmax = bnd ; tightened ++; ; } } else if (coeff < -ZTOLDP2 && cbarjmax0 <PRESOLVE_INF && cup[icol] >= ekkinf) { const double bnd = cbarjmax0 / coeff ; if (rmin < bnd) { # if PRESOLVE_DEBUG > 1 printf("MIN TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymin[i],bnd) ; # endif ymin[i] = rmin = bnd ; tightened ++; ; } } } else { // no_lb // cbarj must not be positive if (coeff > ZTOLDP2 && cbarmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) { const double bnd = cbarmin0 / coeff ; if (rmin < bnd) { # if PRESOLVE_DEBUG > 1 printf("MIN1 TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymin[i],bnd) ; # endif ymin[i] = rmin = bnd ; tightened ++; ; } } else if (coeff < -ZTOLDP2 && cbarmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) { const double bnd = cbarmin0 / coeff ; if (rmax > bnd) { # if PRESOLVE_DEBUG > 1 printf("MAX TIGHT1[%d,%d]: %g --> %g\n",i,hrow[k],ymax[i],bnd) ; # endif ymax[i] = rmax = bnd ; tightened ++; ; } } } } } } # endif // PRESOLVE_TIGHTEN_DUALS /* Is it productive to continue with another pass? Essentially, we need lots of tightening but no fixing. If we fixed any variables, break and process them. */ # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL: pass " << nPass << ": fixed " << (ncols-nfixdown_cols) << " down, " << nfixup_cols << " up, tightened " << tightened << " duals." << std::endl ; # endif if (tightened < 100 || nfixdown_cols < ncols || nfixup_cols) break ; } assert (nfixup_cols <= nfixdown_cols) ; /* Process columns fixed at upper bound. */ if (nfixup_cols) { # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(upper):" ; for (int k = 0 ; k < nfixup_cols ; k++) std::cout << " " << fix_cols[k] ; std::cout << "." << std::endl ; # endif next = make_fixed_action::presolve(prob,fix_cols,nfixup_cols,false,next) ; } /* Process columns fixed at lower bound. */ if (nfixdown_cols < ncols) { int *fixdown_cols = fix_cols+nfixdown_cols ; nfixdown_cols = ncols-nfixdown_cols ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(lower):" ; for (int k = 0 ; k < nfixdown_cols ; k++) std::cout << " " << fixdown_cols[k] ; std::cout << "." << std::endl ; # endif next = make_fixed_action::presolve(prob,fixdown_cols, nfixdown_cols,true,next) ; } /* Now look for variables that, when moved in the favourable direction according to reduced cost, will naturally tighten an inequality to an equality. We can convert that inequality to an equality. See the comments at the head of the routine. Start with logicals. Open a loop and look for suitable rows. At the end of this loop, rows marked with +/-1 will be forced to equality by their logical. Rows marked with +/-2 are inequalities that (perhaps) can be forced to equality using architecturals. Rows marked with 0 are not suitable (range or nonbinding). Note that usefulRowInt_ is 3*nrows_; we'll use the second partition below. */ int *canFix = prob->usefulRowInt_ ; for (int i = 0 ; i < nrows ; i++) { const bool no_rlb = (rlo[i] <= -ekkinf) ; const bool no_rub = (rup[i] >= ekkinf) ; canFix[i] = 0 ; if (no_rub && !no_rlb ) { if (ymin[i] > 0.0) canFix[i] = -1 ; else canFix[i] = -2 ; } else if (no_rlb && !no_rub ) { if (ymax[i] < 0.0) canFix[i] = 1 ; else canFix[i] = 2 ; } # if PRESOLVE_DEBUG > 1 if (abs(canFix[i]) == 1) { std::cout << "NDUAL(eq): candidate row (" << i << ") (" << rlo[i] << "," << rup[i] << "), logical must be " << ((canFix[i] == -1)?"NBUB":"NBLB") << "." << std::endl ; } # endif } /* Can we do a similar trick with architectural variables? Here, we're looking for x<j> such that (1) Exactly one of l<j> or u<j> is infinite. (2) Moving x<j> towards the infinite bound can tighten exactly one constraint i to equality. If x<j> is entangled with other constraints, moving x<j> towards the infinite bound will loosen those constraints. (3) Moving x<j> towards the infinite bound is a good idea according to the cost c<j> (note we don't have to consider reduced cost here). If we can find a suitable x<j>, constraint i can become an equality. This is yet another instance of bound propagation, but we're looking for a very specific pattern: A variable that can be increased arbitrarily in all rows it's entangled with, except for one, which bounds it. And we're going to push the variable so as to make that row an equality. But note what we're *not* doing: No actual comparison of finite bound values to the amount necessary to force an equality. So no worries about accuracy, the bane of bound propagation. Open a loop to scan columns. bindingUp and bindingDown indicate the result of the analysis; -1 says `possible', -2 is ruled out. Test first for condition (1). Column singletons are presumably handled elsewhere. Integer variables need not apply. If both bounds are finite, no need to look further. */ for (int j = 0 ; j < ncols ; j++) { if (hincol[j] <= 1) continue ; if (integerType[j]) continue ; int bindingUp = -1 ; int bindingDown = -1 ; if (cup[j] < ekkinf) bindingUp = -2 ; if (clo[j] > -ekkinf) bindingDown = -2 ; if (bindingUp == -2 && bindingDown == -2) continue ; /* Open a loop to walk the column and check for condition (2). The test for |canFix[i]| != 2 is a non-interference check. We don't want to mess with constraints where we've already decided to use the logical to force equality. Nor do we want to deal with range or nonbinding constraints. */ const CoinBigIndex &kcs = mcstrt[j] ; const CoinBigIndex kce = kcs+hincol[j] ; for (CoinBigIndex k = kcs; k < kce; k++) { const int &i = hrow[k] ; if (abs(canFix[i]) != 2) { bindingUp = -2 ; bindingDown = -2 ; break ; } double aij = colels[k] ; /* For a<ij> > 0 in a <= constraint (canFix = 2), the up direction is binding. For a >= constraint, it'll be the down direction. If the relevant binding code is still -1, set it to the index of the row. Similarly for a<ij> < 0. If this is the second or subsequent binding constraint in that direction, set binding[Up,Down] to -2 (we don't want to get into the business of calculating which constraint is actually binding). */ if (aij > 0.0) { if (canFix[i] == 2) { if (bindingUp == -1) bindingUp = i ; else bindingUp = -2 ; } else { if (bindingDown == -1) bindingDown = i ; else bindingDown = -2 ; } } else { if (canFix[i] == 2) { if (bindingDown == -1) bindingDown = i ; else bindingDown = -2 ; } else { if (bindingUp == -1) bindingUp = i ; else bindingUp = -2 ; } } } if (bindingUp == -2 && bindingDown == -2) continue ; /* If bindingUp > -2, then either no constraint provided a bound (-1) or there's a single constraint (0 <= i < m) that bounds x<j>. If we have just one binding constraint, check that the reduced cost is favourable (c<j> <= 0 for x<j> NBUB at optimum for minimisation). If so, declare that we will force the row to equality (canFix[i] = +/-1). Note that we don't adjust the primal solution value for x<j>. If no constraint provided a bound, we might be headed for unboundedness, but leave that for some other code to determine. */ double cj = cost[j] ; if (bindingUp > -2 && cj <= 0.0) { if (bindingUp >= 0) { canFix[bindingUp] /= 2 ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(eq): candidate row (" << bindingUp << ") (" << rlo[bindingUp] << "," << rup[bindingUp] << "), " << " increasing x(" << j << "), cbar = " << cj << "." << std::endl ; } else { std::cout << "NDUAL(eq): no binding upper bound for x(" << j << "), cbar = " << cj << "." << std::endl ; # endif } } else if (bindingDown > -2 && cj >= 0.0) { if (bindingDown >= 0) { canFix[bindingDown] /= 2 ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(eq): candidate row (" << bindingDown << ") (" << rlo[bindingDown] << "," << rup[bindingDown] << "), " << " decreasing x(" << j << "), cbar = " << cj << "." << std::endl ; } else { std::cout << "NDUAL(eq): no binding lower bound for x(" << j << "), cbar = " << cj << "." << std::endl ; # endif } } } /* We have candidate rows. We've avoided scanning full rows until now, but there's one remaining hazard: if the row contains unfixed integer variables then we don't want to just pin the row to a fixed rhs; that might prevent us from achieving integrality. Scan canFix, count and record suitable rows (use the second partition of usefulRowInt_). */ # if PRESOLVE_DEBUG > 0 int makeEqCandCnt = 0 ; for (int i = 0 ; i < nrows ; i++) { if (abs(canFix[i]) == 1) makeEqCandCnt++ ; } # endif int makeEqCnt = nrows ; for (int i = 0 ; i < nrows ; i++) { if (abs(canFix[i]) == 1) { const CoinBigIndex &krs = mrstrt[i] ; const CoinBigIndex kre = krs+hinrow[i] ; for (CoinBigIndex k = krs ; k < kre ; k++) { const int j = hcol[k] ; if (cup[j] > clo[j] && (integerType[j]||prob->colProhibited2(j))) { canFix[i] = 0 ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(eq): cannot convert row " << i << " to equality; " << "unfixed integer variable x(" << j << ")." << std::endl ; # endif break ; } } if (canFix[i] != 0) canFix[makeEqCnt++] = i ; } } makeEqCnt -= nrows ; # if PRESOLVE_DEBUG > 0 if ((makeEqCandCnt-makeEqCnt) > 0) { std::cout << "NDUAL(eq): rejected " << (makeEqCandCnt-makeEqCnt) << " rows due to unfixed integer variables." << std::endl ; } # endif /* If we've identified inequalities to convert, do the conversion, record the information needed to restore bounds in postsolve, and finally create the postsolve object. */ if (makeEqCnt > 0) { action *bndRecords = new action[makeEqCnt] ; for (int k = 0 ; k < makeEqCnt ; k++) { const int &i = canFix[k+nrows] ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(eq): forcing row " << i << " to equality;" ; if (canFix[i] == -1) std::cout << " dropping b = " << rup[i] << " to " << rlo[i] ; else std::cout << " raising blow = " << rlo[i] << " to " << rup[i] ; std::cout << "." << std::endl ; # endif action &bndRec = bndRecords[(k)] ; bndRec.rlo_ = rlo[i] ; bndRec.rup_ = rup[i] ; bndRec.ndx_ = i ; if (canFix[i] == 1) { rlo[i] = rup[i] ; prob->addRow(i) ; } else if (canFix[i] == -1) { rup[i] = rlo[i] ; prob->addRow(i) ; } } next = new remove_dual_action(makeEqCnt,bndRecords,next) ; } # if PRESOLVE_TIGHTEN_DUALS > 0 delete[] cbarmin ; delete[] cbarmax ; # endif # if COIN_PRESOLVE_TUNING > 0 double thisTime = 0.0 ; if (prob->tuning_) thisTime = CoinCpuTime() ; # endif # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_sol(prob,2,1,1) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving remove_dual_action::presolve, dropped " << droppedRows << " rows, " << droppedColumns << " columns, forced " << makeEqCnt << " equalities" ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) std::cout << " in " << (thisTime-prob->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) ; }