/* Scan the columns and collect indices of columns that have upper and lower bounds within the zero tolerance of one another. Hand this list to make_fixed_action::presolve() to do the heavy lifting. make_fixed_action will compensate for variables which are infeasible, forcing them to feasibility and correcting the row activity, before invoking remove_fixed_action to remove the variable from the problem. If you're confident of feasibility, consider remove_fixed. */ const CoinPresolveAction *make_fixed (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering make_fixed, checking " << prob->ncols_ << " columns." << std::endl ; # endif presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif int ncols = prob->ncols_ ; int *fcols = prob->usefulColumnInt_ ; int nfcols = 0 ; int *hincol = prob->hincol_ ; double *clo = prob->clo_ ; double *cup = prob->cup_ ; for (int i = 0 ; i < ncols ; i++) { if (hincol[i] > 0 && fabs(cup[i]-clo[i]) < ZTOLDP && !prob->colProhibited2(i)) { fcols[nfcols++] = i ; } } /* Call m_f_a::presolve to do the heavy lifting. This will create a new CoinPresolveAction, which will become the head of the list of CoinPresolveAction's currently pointed to by next. No point in going through the effort of a call if there are no fixed variables. */ if (nfcols > 0) next = make_fixed_action::presolve(prob,fcols,nfcols,true,next) ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving make_fixed, fixed " << nfcols << " columns." << std::endl ; # endif # endif return (next) ; }
// We could have implemented this by having each postsolve routine // directly call the next one, but this may make it easier to add debugging checks. void OsiPresolve::postsolve(CoinPostsolveMatrix &prob) { const CoinPresolveAction *paction = paction_; #if PRESOLVE_DEBUG printf("Begin POSTSOLVING\n") ; if (prob.colstat_) { presolve_check_nbasic(&prob); presolve_check_sol(&prob); } presolve_check_duals(&prob); #endif while (paction) { # if PRESOLVE_DEBUG printf("POSTSOLVING %s\n", paction->name()); # endif paction->postsolve(&prob); # if PRESOLVE_DEBUG if (prob.colstat_) { presolve_check_nbasic(&prob); presolve_check_sol(&prob); } # endif paction = paction->next; # if PRESOLVE_DEBUG presolve_check_duals(&prob); # endif } # if PRESOLVE_DEBUG printf("End POSTSOLVING\n") ; # endif #if 0 && PRESOLVE_DEBUG << This block of checks will require some work to get it to compile. >>
/* Recall that in presolve, make_fixed_action forced a bound to fix a variable, then called remove_fixed_action to empty the column. removed_fixed_action left a postsolve object hanging off faction_, and our first act here is to call r_f_a::postsolve to repopulate the columns. The m_f_a postsolve activity consists of relaxing one of the bounds and making sure that the status is still viable (we can potentially eliminate the bound here). */ void make_fixed_action::postsolve(CoinPostsolveMatrix *prob) const { const action *const actions = actions_; const int nactions = nactions_; const bool fix_to_lower = fix_to_lower_; double *clo = prob->clo_; double *cup = prob->cup_; double *sol = prob->sol_ ; unsigned char *colstat = prob->colstat_; /* Repopulate the columns. */ assert(nactions == faction_->nactions_) ; faction_->postsolve(prob); /* Walk the actions: restore each bound and check that the status is still appropriate. Given that we're unfixing a fixed variable, it's safe to assume that the unaffected bound is finite. */ for (int cnt = nactions-1 ; cnt >= 0 ; cnt--) { const action *f = &actions[cnt]; int icol = f->col; double xj = sol[icol] ; assert(faction_->actions_[cnt].col == icol) ; if (fix_to_lower) { double ub = f->bound ; cup[icol] = ub ; if (colstat) { if (ub >= PRESOLVE_INF || xj != ub) { prob->setColumnStatus(icol, CoinPrePostsolveMatrix::atLowerBound) ; } } } else { double lb = f->bound ; clo[icol] = lb ; if (colstat) { if (lb <= -PRESOLVE_INF || xj != lb) { prob->setColumnStatus(icol, CoinPrePostsolveMatrix::atUpperBound) ; } } } } # if PRESOLVE_CONSISTENCY || PRESOLVE_DEBUG presolve_check_threads(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; std::cout << "Leaving make_fixed_action::postsolve." << std::endl ; # endif return ; }
const CoinPresolveAction *implied_free_action::presolve ( CoinPresolveMatrix *prob, const CoinPresolveAction *next, int &fill_level) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering implied_free_action::presolve, fill level " << fill_level << "." << 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 const int startEmptyRows = prob->countEmptyRows() ; const int 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 m = prob->nrows_ ; const int n = prob->ncols_ ; const CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; const int *colIndices = prob->hcol_ ; const double *rowCoeffs = prob->rowels_ ; presolvehlink *rlink = prob->rlink_ ; CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; int *rowIndices = prob->hrow_ ; double *colCoeffs = prob->colels_ ; presolvehlink *clink = prob->clink_ ; /* Column bounds, row bounds, cost, integrality. */ double *clo = prob->clo_ ; double *cup = prob->cup_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *cost = prob->cost_ ; const unsigned char *integerType = prob->integerType_ ; /* Documented as `inhibit x+y+z = 1 mods'. From the code below, it's clear that this is intended to avoid removing SOS equalities with length >= 5 (hardcoded). */ const bool stopSomeStuff = ((prob->presolveOptions()&0x04) != 0) ; /* Ignore infeasibility. `Fix' is overly optimistic. */ const bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; /* Defaults to 0.0. */ const double feasTol = prob->feasibilityTolerance_ ; # if 0 /* Tentatively moved to be a front-end function for useless_constraint_action, much as make_fixed is a front-end for make_fixed_action. This bit of code left for possible tuning. -- lh, 121127 -- Original comment: This needs to be made faster. */ # ifdef COIN_LIGHTWEIGHT_PRESOLVE if (prob->pass_ == 1) { #else if (prob->presolveOptions_&0x10) { # endif next = testRedundant(prob,next) ; if (prob->status_&0x01 != 0) { if ((prob->presolveOptions_&0x4000) != 0) prob->status_ &= !0x01 ; else return (next) ; } # if 1 //def COIN_LIGHTWEIGHT_PRESOLVE } # endif # endif /* implied_free and subst take a fair bit of effort to scan for candidates. This is a hook to allow a presolve driver to avoid that work. */ if (prob->pass_ > 15 && (prob->presolveOptions_&0x10000) != 0) { fill_level = 2 ; return (next) ; } /* Set up to collect implied_free actions. */ action *actions = new action [n] ; # ifdef ZEROFAULT CoinZeroN(reinterpret_cast<char *>(actions),n*sizeof(action)) ; # endif int nactions = 0 ; int *implied_free = prob->usefulColumnInt_ ; int *whichFree = implied_free+n ; int numberFree = 0 ; /* Arrays to hold row activity (row lhs) min and max values. Each row lhs bound is held as two components: a sum of finite column bounds and a count of infinite column bounds. */ int *infiniteDown = new int[m] ; int *infiniteUp = new int[m] ; double *maxDown = new double[m] ; double *maxUp = new double[m] ; /* Overload infiniteUp with row status codes: -1: L(i)/U(i) not yet computed, -2: do not use (empty or useless row), -3: give up (infeasible) -4: chosen as implied free row */ for (int i = 0 ; i < m ; i++) { if (rowLengths[i] > 1) infiniteUp[i] = -1 ; else infiniteUp[i] = -2 ; } // Get rid of rows with prohibited columns if (prob->anyProhibited_) { for (int i = 0 ; i < m ; i++) { CoinBigIndex rStart = rowStarts[i]; CoinBigIndex rEnd = rStart+rowLengths[i]; bool badRow=false; for (CoinBigIndex j = rStart; j < rEnd; ++j) { if (prob->colProhibited(colIndices[j])) { badRow=true; break; } } if (badRow) infiniteUp[i] = -2 ; } } // Can't go on without a suitable finite infinity, can we? #ifdef USE_SMALL_LARGE const double large = 1.0e10 ; #else const double large = 1.0e20 ; #endif /* Decide which columns we're going to look at. There are columns already queued in colsToDo_, but sometimes we want to look at all of them. Don't suck in prohibited columns. See comments at the head of the routine for fill_level. NOTE the overload on usefulColumnInt_. It was assigned above to whichFree (indices of interesting columns). We'll be ok because columns are consumed out of look at one per main loop iteration, but not all columns are interesting. Original comment: if gone from 2 to 3 look at all */ int numberLook = prob->numberColsToDo_ ; int iLook ; int *look = prob->colsToDo_ ; if (fill_level < 0) { look = prob->usefulColumnInt_+n ; if (!prob->anyProhibited()) { CoinIotaN(look,n,0) ; numberLook = n ; } else { numberLook = 0 ; for (iLook = 0 ; iLook < n ; iLook++) if (!prob->colProhibited(iLook)) look[numberLook++] = iLook ; } } /* Step through the columns of interest looking for suitable x(tgt). Interesting columns are limited by number of nonzeros to minimise fill-in during substitution. */ bool infeas = false ; const int maxLook = abs(fill_level) ; for (iLook = 0 ; iLook < numberLook ; iLook++) { const int tgtcol = look[iLook] ; const int tgtcol_len = colLengths[tgtcol] ; if (tgtcol_len <= 0 || tgtcol_len > maxLook) continue ; /* Set up to reconnoiter the column. The initial value for ait_max is chosen to make sure that anything that satisfies the stability check is big enough to use (though we'd clearly like something better). */ const CoinBigIndex kcs = colStarts[tgtcol] ; const CoinBigIndex kce = kcs+tgtcol_len ; const bool singletonCol = (tgtcol_len == 1) ; bool possibleRow = false ; bool singletonRow = false ; double ait_max = 20*ZTOLDP2 ; /* If this is a singleton column, the only concern is that the row is not a singleton row (that has its own, simpler, transform: slack_doubleton). But make sure we're not dealing with some tiny a(it). Note that there's no point in marking a singleton row. By definition, we won't encounter it again. */ if (singletonCol) { const int i = rowIndices[kcs] ; singletonRow = (rowLengths[i] == 1) ; possibleRow = (fabs(colCoeffs[kcs]) > ZTOLDP2) ; } else { /* If the column is not a singleton, we'll need a numerically stable substitution formula. Check that this is possible. One of the entangled rows must be an equality with a numerically stable coefficient, at least .1*MAX{i}a(it). */ for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) { const int i = rowIndices[kcol] ; if (rowLengths[i] == 1) { singletonRow = true ; break ; } const double abs_ait = fabs(colCoeffs[kcol]) ; ait_max = CoinMax(ait_max,abs_ait) ; if (fabs(rlo[i]-rup[i]) < feasTol && abs_ait > .1*ait_max) { possibleRow = true ; } } } if (singletonRow || !possibleRow) continue ; /* The column has possibilities. Walk the column, calculate row activity bounds L(i) and U(i) for suitable entangled rows, then calculate the improvement (if any) on the column bounds for l(j) and u(j). The goal is to satisfy the implied free condition over all entangled rows and find at least one row suitable for a substitution formula (if the column is not a natural singleton). Suitable: If this is a natural singleton, we need to look at the single entangled constraint. If we're attempting to create a singleton by substitution, only look at equalities with stable coefficients. If x(t) is integral, make sure the scaled rhs will be integral. */ # if PRESOLVE_DEBUG > 2 std::cout << " Checking x(" << tgtcol << "), " << tgtcol_len << " nonzeros" << ", l(" << tgtcol << ") " << clo[tgtcol] << ", u(" << tgtcol << ") " << cup[tgtcol] << ", c(" << tgtcol << ") " << cost[tgtcol] << "." << std::endl ; # endif const double lt = clo[tgtcol] ; const double ut = cup[tgtcol] ; double impliedLow = -COIN_DBL_MAX ; double impliedHigh = COIN_DBL_MAX ; int subst_ndx = -1 ; int subst_len = n ; for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) { const int i = rowIndices[kcol] ; assert(infiniteUp[i] != -3) ; if (infiniteUp[i] <= -2) continue ; const double ait = colCoeffs[kcol] ; const int leni = rowLengths[i] ; const double rloi = rlo[i] ; const double rupi = rup[i] ; /* A suitable row for substitution must * be an equality; * the entangled coefficient must be large enough to be numerically stable; * if x(t) is integer, the constant term in the substitution formula must be integer. */ bool rowiOK = (fabs(rloi-rupi) < feasTol) && (fabs(ait) > .1*ait_max) ; rowiOK = rowiOK && ((integerType[tgtcol] == 0) || (fabs((rloi/ait)-floor((rloi/ait)+0.5)) < feasTol)) ; /* If we don't already have L(i) and U(i), calculate now. Check for useless and infeasible constraints when that's done. */ int infUi = 0 ; int infLi = 0 ; double maxUi = 0.0 ; double maxLi = 0.0 ; const CoinBigIndex krs = rowStarts[i] ; const CoinBigIndex kre = krs+leni ; if (infiniteUp[i] == -1) { for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const double aik = rowCoeffs[krow] ; const int k = colIndices[krow] ; const double lk = clo[k] ; const double uk = cup[k] ; if (aik > 0.0) { if (uk < large) maxUi += uk*aik ; else ++infUi ; if (lk > -large) maxLi += lk*aik ; else ++infLi ; } else if (aik < 0.0) { if (uk < large) maxLi += uk*aik ; else ++infLi ; if (lk > -large) maxUi += lk*aik ; else ++infUi ; } } const double maxUinf = maxUi+infUi*1.0e31 ; const double maxLinf = maxLi-infLi*1.0e31 ; if (maxUinf <= rupi+feasTol && maxLinf >= rloi-feasTol) { infiniteUp[i] = -2 ; } else if (maxUinf < rloi-feasTol && !fixInfeasibility) { prob->status_|= 1 ; infeas = true ; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) << i << rloi << rupi << CoinMessageEol ; infiniteUp[i] = -3 ; } else if (maxLinf > rupi+feasTol && !fixInfeasibility) { prob->status_|= 1 ; infeas = true ; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) << i << rloi << rupi << CoinMessageEol ; infiniteUp[i] = -3 ; } else { infiniteUp[i] = infUi ; infiniteDown[i] = infLi ; maxUp[i] = maxUi ; maxDown[i] = maxLi ; } } else { infUi = infiniteUp[i] ; infLi = infiniteDown[i] ; maxUi = maxUp[i] ; maxLi = maxDown[i] ; } # if PRESOLVE_DEBUG > 2 std::cout << " row(" << i << ") " << leni << " nonzeros, blow " << rloi << ", L (" << infLi << "," << maxLi << "), U (" << infUi << "," << maxUi << "), b " << rupi ; if (infeas) std::cout << " infeas" ; if (infiniteUp[i] == -2) std::cout << " useless" ; std::cout << "." << std::endl ; # endif /* If we're infeasible, no sense checking further; escape the implied bound loop. The other possibility is that we've just discovered the constraint is useless, in which case we just move on to the next one in the column. */ if (infeas) break ; if (infiniteUp[i] == -2) continue ; assert(infiniteUp[i] >= 0 && infiniteUp[i] <= leni) ; /* At this point we have L(i) and U(i), expressed as finite and infinite components, and constraint i is neither useless or infeasible. Calculate the implied bounds l'(t) and u'(t) on x(t). The calculation (for a(it) > 0) is u'(t) <= (b(i) - (L(i)-a(it)l(t)))/a(it) = l(t)+(b(i)-L(i))/a(it) l'(t) >= (blow(i) - (U(i)-a(it)u(t)))/a(it) = u(t)+(blow(i)-U(i))/a(it) Insert the appropriate flips for a(it) < 0. Notice that if there's exactly one infinite contribution to L(i) or U(i) and x(t) is responsible, then the finite portion of L(i) or U(i) is already correct. Cut some slack for possible numerical inaccuracy if the finite portion of L(i) or U(i) is very large. If the new bound is very large, force it to infinity. */ double ltprime = -COIN_DBL_MAX ; double utprime = COIN_DBL_MAX ; if (ait > 0.0) { if (rloi > -large) { if (!infUi) { assert(ut < large) ; ltprime = ut+(rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxUi) ; } else if (infUi == 1 && ut > large) { ltprime = (rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxUi) ; } else { ltprime = -COIN_DBL_MAX ; } impliedLow = CoinMax(impliedLow,ltprime) ; } if (rupi < large) { if (!infLi) { assert(lt > -large) ; utprime = lt+(rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxLi) ; } else if (infLi == 1 && lt < -large) { utprime = (rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxLi) ; } else { utprime = COIN_DBL_MAX ; } impliedHigh = CoinMin(impliedHigh,utprime) ; } } else { if (rloi > -large) { if (!infUi) { assert(lt > -large) ; utprime = lt+(rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxUi) ; } else if (infUi == 1 && lt < -large) { utprime = (rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxUi) ; } else { utprime = COIN_DBL_MAX ; } impliedHigh = CoinMin(impliedHigh,utprime) ; } if (rupi < large) { if (!infLi) { assert(ut < large) ; ltprime = ut+(rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxLi) ; } else if (infLi == 1 && ut > large) { ltprime = (rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxLi) ; } else { ltprime = -COIN_DBL_MAX ; } impliedLow = CoinMax(impliedLow,ltprime) ; } } # if PRESOLVE_DEBUG > 2 std::cout << " row(" << i << ") l'(" << tgtcol << ") " << ltprime << ", u'(" << tgtcol << ") " << utprime ; if (lt <= impliedLow && impliedHigh <= ut) std::cout << "; implied free satisfied" ; std::cout << "." << std::endl ; # endif /* For x(t) integral, see if a substitution formula based on row i will preserve integrality. The final check in this clause aims to preserve SOS equalities (i.e., don't eliminate a non-trivial SOS equality from the system using this transform). Note that this can't be folded into the L(i)/U(i) loop because the answer changes with x(t). Original comment: can only accept if good looking row */ if (integerType[tgtcol]) { possibleRow = true ; bool allOnes = true ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double scaled_aij = rowCoeffs[krow]/ait ; if (fabs(scaled_aij) != 1.0) allOnes = false ; if (!integerType[j] || fabs(scaled_aij-floor(scaled_aij+0.5)) > feasTol) { possibleRow = false ; break ; } } if (rloi == 1.0 && leni >= 5 && stopSomeStuff && allOnes) possibleRow = false ; rowiOK = rowiOK && possibleRow ; } /* Do we have a winner? If we have an incumbent, prefer the one with fewer coefficients. */ if (rowiOK) { if (subst_ndx < 0 || (leni < subst_len)) { # if PRESOLVE_DEBUG > 2 std::cout << " row(" << i << ") now candidate for x(" << tgtcol << ")." << std::endl ; # endif subst_ndx = i ; subst_len = leni ; } } } if (infeas) break ; /* Can we do the transform? If so, subst_ndx will have a valid row. Record the implied free variable and the equality we'll use to substitute it out. Take the row out of the running --- we can't use the same row for two substitutions. */ if (lt <= impliedLow && impliedHigh <= ut && (subst_ndx >= 0 || singletonRow)) { implied_free[numberFree] = subst_ndx ; infiniteUp[subst_ndx] = -4 ; whichFree[numberFree++] = tgtcol ; # if PRESOLVE_DEBUG > 1 std::cout << " x(" << tgtcol << ") implied free by row " << subst_ndx << std::endl ; # endif } } delete[] infiniteDown ; delete[] infiniteUp ; delete[] maxDown ; delete[] maxUp ; /* If we're infeasible, there's nothing more to be done. */ if (infeas) { # if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0 std::cout << " IMPLIED_FREE: infeasible." << std::endl ; # endif return (next) ; } /* We have a list of implied free variables, each with a row that can be used to substitute the variable to singleton status if the variable is not a natural singleton. The loop here will only process natural singletons. We'll hand the remainder to subst_constraint_action below, if there is a remainder. The natural singletons processed here are compressed out of whichFree and implied_free. */ int unprocessed = 0 ; for (iLook = 0 ; iLook < numberFree ; iLook++) { const int tgtcol = whichFree[iLook] ; if (colLengths[tgtcol] != 1) { whichFree[unprocessed] = whichFree[iLook] ; implied_free[unprocessed] = implied_free[iLook] ; unprocessed++ ; continue ; } const int tgtrow = implied_free[iLook] ; const int tgtrow_len = rowLengths[tgtrow] ; const CoinBigIndex kcs = colStarts[tgtcol] ; const double tgtcol_coeff = colCoeffs[kcs] ; const double tgtcol_cost = cost[tgtcol] ; const CoinBigIndex krs = rowStarts[tgtrow] ; const CoinBigIndex kre = krs+tgtrow_len ; if (tgtcol_cost != 0.0) { // Check costs don't make unstable //double minOldCost=COIN_DBL_MAX; double maxOldCost=0.0; //double minNewCost=COIN_DBL_MAX; double maxNewCost=0.0; for (CoinBigIndex krow = krs ; krow < kre ; krow++) { const int j = colIndices[krow] ; if (j != tgtcol) { double oldCost = cost[j] ; double newCost = oldCost - (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ; oldCost = fabs(oldCost); newCost = fabs(newCost); //minOldCost=CoinMin(minOldCost,oldCost); maxOldCost=CoinMax(maxOldCost,oldCost); //minNewCost=CoinMin(minNewCost,newCost); maxNewCost=CoinMax(maxNewCost,newCost); } } if (maxNewCost>1000.0*(maxOldCost+1.0) && maxOldCost) { //printf("too big %d tgtcost %g maxOld %g maxNew %g\n", // tgtcol,tgtcol_cost,maxOldCost,maxNewCost); continue; } } /* Initialise the postsolve action. We need to remember the row and column. */ action *s = &actions[nactions++] ; s->row = tgtrow ; s->col = tgtcol ; s->clo = clo[tgtcol] ; s->cup = cup[tgtcol] ; s->rlo = rlo[tgtrow] ; s->rup = rup[tgtrow] ; s->ninrow = tgtrow_len ; s->rowels = presolve_dupmajor(rowCoeffs,colIndices,tgtrow_len,krs) ; s->costs = NULL ; /* We're processing a singleton, hence no substitutions in the matrix, but we do need to fix up the cost vector. The substitution formula is x(t) = (rhs(i) - SUM{j\t}a(ik)x(k))/a(it) hence c'(k) = c(k)-c(t)a(ik)/a(it) and there's a constant offset c(t)rhs(i)/a(it). where rhs(i) is one of blow(i) or b(i). For general constraints where blow(i) != b(i), we need to take a bit of care. If only one of blow(i) or b(i) is finite, that's the one to use. Where we have two finite but unequal bounds, choose the bound that will result in the most favourable value for x(t). For minimisation, if c(t) < 0 we want to maximise x(t), so choose b(i) if a(it) > 0, blow(i) if a(it) < 0. A bit of case analysis says choose b(i) when c(t)a(it) < 0, blow(i) when c(t)a(it) > 0. We shouldn't be here if both row bounds are infinite. Fortunately, the objective coefficients are not affected by this. */ if (tgtcol_cost != 0.0) { double tgtrow_rhs = rup[tgtrow] ; if (fabs(rlo[tgtrow]-rup[tgtrow]) > feasTol) { const double rlot = rlo[tgtrow] ; const double rupt = rup[tgtrow] ; if (rlot > -COIN_DBL_MAX && rupt < COIN_DBL_MAX) { if ((tgtcol_cost*tgtcol_coeff) > 0) tgtrow_rhs = rlot ; else tgtrow_rhs = rupt ; } else if (rupt >= COIN_DBL_MAX) { tgtrow_rhs = rlot ; } } assert(fabs(tgtrow_rhs) <= large) ; double *save_costs = new double[tgtrow_len] ; for (CoinBigIndex krow = krs ; krow < kre ; krow++) { const int j = colIndices[krow] ; save_costs[krow-krs] = cost[j] ; cost[j] -= (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ; } prob->change_bias((tgtcol_cost*tgtrow_rhs)/tgtcol_coeff) ; cost[tgtcol] = 0.0 ; s->costs = save_costs ; } /* Remove the row from the column-major representation, queuing up each column for reconsideration. Then remove the row from the row-major representation. */ for (CoinBigIndex krow = krs ; krow < kre ; krow++) { const int j = colIndices[krow] ; presolve_delete_from_col(tgtrow,j,colStarts,colLengths,rowIndices, colCoeffs) ; if (colLengths[j] == 0) { PRESOLVE_REMOVE_LINK(prob->clink_,j) ; } else { prob->addCol(j) ; } } PRESOLVE_REMOVE_LINK(clink,tgtcol) ; colLengths[tgtcol] = 0 ; PRESOLVE_REMOVE_LINK(rlink,tgtrow) ; rowLengths[tgtrow] = 0 ; rlo[tgtrow] = 0.0 ; rup[tgtrow] = 0.0 ; } /* We're done with the natural singletons. Trim actions to length and create the postsolve object. */ if (nactions) { # if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0 printf("NIMPLIED FREE: %d\n", nactions) ; # endif action *actions1 = new action[nactions] ; CoinMemcpyN(actions, nactions, actions1) ; next = new implied_free_action(nactions,actions1,next) ; } delete [] actions ; # if PRESOLVE_DEBUG > 0 std::cout << " IMPLIED_FREE: identified " << numberFree << " implied free transforms, processed " << numberFree-unprocessed << " natural singletons." << std::endl ; # endif /* Now take a stab at the columns that aren't natural singletons, if there are any left. */ if (unprocessed != 0) { // if not integer - don't allow much fill if (!prob->anyInteger()) { int numberFree=unprocessed; int nBad=0; unprocessed=0; // Take out ones that make much denser or might lead to instability /* Unpack the row- and column-major representations. */ CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; double *rowCoeffs = prob->rowels_ ; int *colIndices = prob->hcol_ ; CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; double *colCoeffs = prob->colels_ ; int *rowIndices = prob->hrow_ ; /* 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. NOTE that usefulColumnInt_ is already in use for parameters implied_free and whichFree when this routine is called from implied_free. */ 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 tgtrow = implied_free[iLook] ; 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 ; } if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (2)." << std::endl ; # endif continue ; } /* 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 ; } CoinBigIndex tgtrs = rowStarts[tgtrow] ; CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ; // 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 */ CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ; CoinBigIndex start=colStarts[tgtcol]; CoinBigIndex end = start+colLengths[tgtcol]; numberBadElements=0; int numberFill=-rowLengths[tgtrow]; for (int colndx = start ; colndx < end ; ++colndx) { int i = rowIndices[colndx] ; if (i == tgtrow) continue ; double ait = colCoeffs[colndx] ; double coeff_factor = -ait/tgtcoeff ; CoinBigIndex krs = rowStarts[i] ; CoinBigIndex kre = krs+rowLengths[i] ; /* 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) ; numberFill += check_row(rowStarts,rowCoeffs,colIndices, rowLengths,coeff_factor,tolerance,i,tgtrow); } if (numberBadElements||3*numberFill>2*(colLengths[tgtcol]+rowLengths[tgtrow])) { //printf("Bad subst col %d row %d - %d small elements, fill %d\n", // tgtcol,tgtrow,numberBadElements,numberFill); if (numberBadElements) nBad++; } else { whichFree[unprocessed]=tgtcol; implied_free[unprocessed++]=tgtrow; //printf("Good subst col %d row %d - fill %d\n", // tgtcol,tgtrow,numberFill); } } /* 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]) ; #if CLP_USEFUL_PRINTOUT printf("%d allowed through out of %d - %d on coefficient\n", unprocessed,numberFree,nBad); #endif } next = subst_constraint_action::presolve(prob,implied_free,whichFree, unprocessed,next,maxLook) ; } /* Give some feedback to the presolve driver. If we aren't finding enough candidates and haven't reached the limit, bump fill_level and return a negated value. The presolve driver can tweak this value or simply return it on the next call. See the top of the routine for a full explanation. */ if (numberFree < 30 && maxLook < prob->maxSubstLevel_) { fill_level = -(maxLook+1) ; } else { fill_level = maxLook ; } # if COIN_PRESOLVE_TUNING > 0 double thisTime ; if (prob->tuning_) thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 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 droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving implied_free_action::presolve, fill level " << fill_level << ", " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
void implied_free_action::postsolve(CoinPostsolveMatrix *prob) const { const action *const actions = actions_ ; const int nactions = nactions_ ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 char *cdone = prob->cdone_ ; char *rdone = prob->rdone_ ; # if PRESOLVE_DEBUG > 0 std::cout << "Entering implied_free_action::postsolve, " << nactions << " transforms to undo." << std::endl ; # endif presolve_check_threads(prob) ; presolve_check_free_list(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # endif /* Unpack the column-major representation. */ CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; int *rowIndices = prob->hrow_ ; double *colCoeffs = prob->colels_ ; CoinBigIndex *link = prob->link_ ; CoinBigIndex &free_list = prob->free_list_ ; /* Column bounds, row bounds, and cost. */ double *clo = prob->clo_ ; double *cup = prob->cup_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *cost = prob->cost_ ; /* Solution, reduced costs, duals, row activity. */ double *sol = prob->sol_ ; double *rcosts = prob->rcosts_ ; double *acts = prob->acts_ ; double *rowduals = prob->rowduals_ ; /* In your dreams ... hardwired to minimisation. */ const double maxmin = 1.0 ; /* And a suitably small infinity. */ const double large = 1.0e20 ; /* Open a loop to restore the row and column for each action. Start by unpacking the action. There won't be saved costs if the original cost c(t) was zero. */ for (const action *f = &actions[nactions-1] ; actions <= f ; f--) { const int tgtrow = f->row ; const int tgtcol = f->col ; const int tgtrow_len = f->ninrow ; const double *tgtrow_coeffs = f->rowels ; const int *tgtrow_cols = reinterpret_cast<const int *>(tgtrow_coeffs+tgtrow_len) ; const double *saved_costs = f->costs ; # if PRESOLVE_DEBUG > 2 std::cout << " restoring col " << tgtcol << " row " << tgtrow ; if (saved_costs != 0) std::cout << ", modified costs" ; std::cout << "." << std::endl ; # endif /* Restore the target row and column and the original cost coefficients. We need to initialise the target column; for others, just bump the coefficient count. While we're restoring the row, pick off the coefficient for x(t) and calculate the row activity. */ double tgt_coeff = 0.0 ; double tgtrow_act = 0.0 ; for (int krow = 0 ; krow < tgtrow_len ; krow++) { const int j = tgtrow_cols[krow] ; const double atj = tgtrow_coeffs[krow] ; assert(free_list >= 0 && free_list < prob->bulk0_) ; CoinBigIndex kk = free_list ; free_list = link[free_list] ; link[kk] = colStarts[j] ; colStarts[j] = kk ; colCoeffs[kk] = atj ; rowIndices[kk] = tgtrow ; if (saved_costs) cost[j] = saved_costs[krow] ; if (j == tgtcol) { colLengths[j] = 1 ; clo[tgtcol] = f->clo ; cup[tgtcol] = f->cup ; rcosts[j] = -cost[tgtcol]/atj ; tgt_coeff = atj ; } else { colLengths[j]++ ; tgtrow_act += atj*sol[j] ; } } rlo[tgtrow] = f->rlo ; rup[tgtrow] = f->rup ; PRESOLVEASSERT(fabs(tgt_coeff) > ZTOLDP) ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 cdone[tgtcol] = IMPLIED_FREE ; rdone[tgtrow] = IMPLIED_FREE ; # endif # if PRESOLVE_CONSISTENCY > 0 presolve_check_free_list(prob) ; # endif /* Calculate a value for x(t). We have two possible values for x(t), calculated against the upper and lower bound of the constraint. x(t) could end up at one of its original bounds or it could end up strictly within bounds. In either event, the constraint will be tight. The code simply forces the calculated value for x(t) to be within bounds. Arguably it should complain more loudly as this likely indicates algorithmic error or numerical inaccuracy. You'll get a warning if debugging is enabled. */ double xt_lo,xt_up ; if (tgt_coeff > 0) { xt_lo = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ; xt_up = (rup[tgtrow]-tgtrow_act)/tgt_coeff ; } else { xt_lo = (rup[tgtrow]-tgtrow_act)/tgt_coeff ; xt_up = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ; } const double lt = clo[tgtcol] ; const double ut = cup[tgtcol] ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 bool chklo = true ; bool chkup = true ; if (tgt_coeff > 0) { if (rlo[tgtrow] < -large) chklo = false ; if (rup[tgtrow] > large) chkup = false ; } else { if (rup[tgtrow] > large) chklo = false ; if (rlo[tgtrow] < -large) chkup = false ; } if (chklo && (xt_lo < lt-prob->ztolzb_)) { std::cout << " LOW CSOL (implied_free): x(" << tgtcol << ") lb " << lt << ", sol = " << xt_lo << ", err " << (lt-xt_lo) << "." << std::endl ; } if (chkup && (xt_up > ut+prob->ztolzb_)) { std::cout << " HIGH CSOL (implied_free): x(" << tgtcol << ") ub " << ut << ", sol = " << xt_up << ", err " << (xt_up-ut) << "." << std::endl ; } # if PRESOLVE_DEBUG > 2 std::cout << " x(" << tgtcol << ") lb " << lt << " lo " << xt_lo << ", up " << xt_up << " ub " << ut << "." << std::endl ; # endif # endif xt_lo = CoinMax(xt_lo,lt) ; xt_up = CoinMin(xt_up,ut) ; /* Time to make x(t) basic and the logical nonbasic. The sign of the dual determines the tight row bound, which in turn determines the value of x(t). Because the row is tight, activity is by definition equal to the bound. Coin convention is that a <= constraint puts a lower bound on the slack and a >= constraint puts an upper bound on the slack. Case analysis (minimisation) says: dual >= 0 ==> reduced cost <= 0 ==> NBUB ==> finite rlo dual <= 0 ==> reduced cost >= 0 ==> NBLB ==> finite rup */ const double ct = maxmin*cost[tgtcol] ; double possibleDual = ct/tgt_coeff ; rowduals[tgtrow] = possibleDual ; if (possibleDual >= 0 && rlo[tgtrow] > -large) { sol[tgtcol] = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ; acts[tgtrow] = rlo[tgtrow] ; prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atUpperBound) ; } else if (possibleDual <= 0 && rup[tgtrow] < large) { sol[tgtcol] = (rup[tgtrow]-tgtrow_act)/tgt_coeff ; acts[tgtrow] = rup[tgtrow] ; prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atLowerBound) ; } else { assert(rup[tgtrow] < large || rlo[tgtrow] > -large) ; if (rup[tgtrow] < large) { sol[tgtcol] = (rup[tgtrow]-tgtrow_act)/tgt_coeff ; acts[tgtrow] = rup[tgtrow] ; prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atLowerBound) ; } else { sol[tgtcol] = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ; acts[tgtrow] = rlo[tgtrow] ; prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atUpperBound) ; } # if PRESOLVE_DEBUG > 0 std::cout << "BAD ROW STATUS row " << tgtrow << ": dual " << rowduals[tgtrow] << " but row " << ((rowduals[tgtrow] > 0)?"upper":"lower") << " bound is not finite; forcing status " << prob->rowStatusString(tgtrow) << "." << std::endl ; # endif } prob->setColumnStatus(tgtcol,CoinPrePostsolveMatrix::basic) ; rcosts[tgtcol] = 0.0 ; # if PRESOLVE_DEBUG > 2 std::cout << " x(" << tgtcol << ") B dj " << rcosts[tgtcol] << "." << std::endl ; std::cout << " row " << tgtrow << " dual " << rowduals[tgtrow] << "." << std::endl ; # endif PRESOLVEASSERT(acts[tgtrow] >= rlo[tgtrow]-1.0e-5 && acts[tgtrow] <= rup[tgtrow]+1.0e-5) ; # if PRESOLVE_DEBUG > 2 /* Debug code to compare the reduced costs against a calculation from scratch as c(j)-ya(j). */ for (int krow = 0 ; krow < tgtrow_len ; krow++) { const int j = tgtrow_cols[krow] ; const int lenj = colLengths[j] ; double dj = cost[j] ; CoinBigIndex kcol = colStarts[j] ; for (int cntj = 0 ; cntj < lenj ; ++cntj) { const int i = rowIndices[kcol] ; const double aij = colCoeffs[kcol] ; dj -= rowduals[i]*aij ; kcol = link[kcol] ; } if (fabs(dj-rcosts[j]) > 1.0e-3) { std::cout << " cbar(" << j << ") update " << rcosts[j] << " expected " << dj << " err " << fabs(dj-rcosts[j]) << "." << std::endl ; } } # endif } # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_threads(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving implied_free_action::postsolve." << std::endl ; # endif # endif return ; }
/* This version of presolve returns a pointer to a new presolved model. NULL if infeasible doStatus controls activities required to transform an existing solution to match the presolved problem. I'd (lh) argue that this should default to false, but to maintain previous behaviour it defaults to true. Really, this is only useful if you've already optimised before applying presolve and also want to work with the solution after presolve. I think that this is the less common case. The more common situation is to apply presolve before optimising. */ OsiSolverInterface * OsiPresolve::presolvedModel(OsiSolverInterface & si, double feasibilityTolerance, bool keepIntegers, int numberPasses, const char * prohibited, bool doStatus, const char * rowProhibited) { ncols_ = si.getNumCols(); nrows_ = si.getNumRows(); nelems_ = si.getNumElements(); numberPasses_ = numberPasses; double maxmin = si.getObjSense(); originalModel_ = &si; delete [] originalColumn_; originalColumn_ = new int[ncols_]; delete [] originalRow_; originalRow_ = new int[nrows_]; int i; for (i=0;i<ncols_;i++) originalColumn_[i]=i; for (i=0;i<nrows_;i++) originalRow_[i]=i; // result is 0 - okay, 1 infeasible, -1 go round again int result = -1; // User may have deleted - its their responsibility presolvedModel_=NULL; // Messages CoinMessages messages = CoinMessage(si.messages().language()); // Only go round 100 times even if integer preprocessing int totalPasses=100; while (result==-1) { // make new copy delete presolvedModel_; presolvedModel_ = si.clone(); totalPasses--; // drop integer information if wanted if (!keepIntegers) { int i; for (i=0;i<ncols_;i++) presolvedModel_->setContinuous(i); } CoinPresolveMatrix prob(ncols_, maxmin, presolvedModel_, nrows_, nelems_,doStatus,nonLinearValue_,prohibited, rowProhibited); // make sure row solution correct if (doStatus) { double *colels = prob.colels_; int *hrow = prob.hrow_; CoinBigIndex *mcstrt = prob.mcstrt_; int *hincol = prob.hincol_; int ncols = prob.ncols_; double * csol = prob.sol_; double * acts = prob.acts_; int nrows = prob.nrows_; int colx; memset(acts,0,nrows*sizeof(double)); for (colx = 0; colx < ncols; ++colx) { double solutionValue = csol[colx]; for (int i=mcstrt[colx]; i<mcstrt[colx]+hincol[colx]; ++i) { int row = hrow[i]; double coeff = colels[i]; acts[row] += solutionValue*coeff; } } } // move across feasibility tolerance prob.feasibilityTolerance_ = feasibilityTolerance; /* Do presolve. Allow for the possibility that presolve might be ineffective (i.e., we're feasible but no postsolve actions are queued. */ paction_ = presolve(&prob) ; result = 0 ; // Get rid of useful arrays prob.deleteStuff(); /* This we don't need to do unless presolve actually reduced the system. */ if (prob.status_==0&&paction_) { // Looks feasible but double check to see if anything slipped through int n = prob.ncols_; double * lo = prob.clo_; double * up = prob.cup_; int i; for (i=0;i<n;i++) { if (up[i]<lo[i]) { if (up[i]<lo[i]-1.0e-8) { // infeasible prob.status_=1; } else { up[i]=lo[i]; } } } n = prob.nrows_; lo = prob.rlo_; up = prob.rup_; for (i=0;i<n;i++) { if (up[i]<lo[i]) { if (up[i]<lo[i]-1.0e-8) { // infeasible prob.status_=1; } else { up[i]=lo[i]; } } } } /* If we're feasible, load the presolved system into the solver. Presumably we could skip model update and copying of status and solution if presolve took no action. */ if (prob.status_ == 0) { prob.update_model(presolvedModel_, nrows_, ncols_, nelems_); # if PRESOLVE_CONSISTENCY if (doStatus) { int basicCnt = 0 ; int basicColumns = 0; int i ; CoinPresolveMatrix::Status status ; for (i = 0 ; i < prob.ncols_ ; i++) { status = prob.getColumnStatus(i); if (status == CoinPrePostsolveMatrix::basic) basicColumns++ ; } basicCnt = basicColumns; for (i = 0 ; i < prob.nrows_ ; i++) { status = prob.getRowStatus(i); if (status == CoinPrePostsolveMatrix::basic) basicCnt++ ; } # if PRESOLVE_DEBUG presolve_check_nbasic(&prob) ; # endif if (basicCnt>prob.nrows_) { // Take out slacks double * acts = prob.acts_; double * rlo = prob.rlo_; double * rup = prob.rup_; double infinity = si.getInfinity(); for (i = 0 ; i < prob.nrows_ ; i++) { status = prob.getRowStatus(i); if (status == CoinPrePostsolveMatrix::basic) { basicCnt-- ; double down = acts[i]-rlo[i]; double up = rup[i]-acts[i]; if (CoinMin(up,down)<infinity) { if (down<=up) prob.setRowStatus(i,CoinPrePostsolveMatrix::atLowerBound); else prob.setRowStatus(i,CoinPrePostsolveMatrix::atUpperBound); } else { prob.setRowStatus(i,CoinPrePostsolveMatrix::isFree); } } if (basicCnt==prob.nrows_) break; } } } #endif /* Install the status and primal solution, if we've been carrying them along. The code that copies status is efficient but brittle. The current definitions for CoinWarmStartBasis::Status and CoinPrePostsolveMatrix::Status are in one-to-one correspondence. This code will fail if that ever changes. */ if (doStatus) { presolvedModel_->setColSolution(prob.sol_); CoinWarmStartBasis *basis = dynamic_cast<CoinWarmStartBasis *>(presolvedModel_->getEmptyWarmStart()); basis->resize(prob.nrows_,prob.ncols_); int i; for (i=0;i<prob.ncols_;i++) { CoinWarmStartBasis::Status status = static_cast<CoinWarmStartBasis::Status> (prob.getColumnStatus(i)); basis->setStructStatus(i,status); } for (i=0;i<prob.nrows_;i++) { CoinWarmStartBasis::Status status = static_cast<CoinWarmStartBasis::Status> (prob.getRowStatus(i)); basis->setArtifStatus(i,status); } presolvedModel_->setWarmStart(basis); delete basis ; delete [] prob.sol_; delete [] prob.acts_; delete [] prob.colstat_; prob.sol_=NULL; prob.acts_=NULL; prob.colstat_=NULL; } /* Copy original column and row information from the CoinPresolveMatrix object so it'll be available for postsolve. */ int ncolsNow = presolvedModel_->getNumCols(); memcpy(originalColumn_,prob.originalColumn_,ncolsNow*sizeof(int)); delete [] prob.originalColumn_; prob.originalColumn_=NULL; int nrowsNow = presolvedModel_->getNumRows(); memcpy(originalRow_,prob.originalRow_,nrowsNow*sizeof(int)); delete [] prob.originalRow_; prob.originalRow_=NULL; // now clean up integer variables. This can modify original { int numberChanges=0; const double * lower0 = originalModel_->getColLower(); const double * upper0 = originalModel_->getColUpper(); const double * lower = presolvedModel_->getColLower(); const double * upper = presolvedModel_->getColUpper(); for (i=0;i<ncolsNow;i++) { if (!presolvedModel_->isInteger(i)) continue; int iOriginal = originalColumn_[i]; double lowerValue0 = lower0[iOriginal]; double upperValue0 = upper0[iOriginal]; double lowerValue = ceil(lower[i]-1.0e-5); double upperValue = floor(upper[i]+1.0e-5); presolvedModel_->setColBounds(i,lowerValue,upperValue); if (lowerValue>upperValue) { numberChanges++; presolvedModel_->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, messages) <<iOriginal <<lowerValue <<upperValue <<CoinMessageEol; result=1; } else { if (lowerValue>lowerValue0+1.0e-8) { originalModel_->setColLower(iOriginal,lowerValue); numberChanges++; } if (upperValue<upperValue0-1.0e-8) { originalModel_->setColUpper(iOriginal,upperValue); numberChanges++; } } } if (numberChanges) { presolvedModel_->messageHandler()->message(COIN_PRESOLVE_INTEGERMODS, messages) <<numberChanges <<CoinMessageEol; if (!result&&totalPasses>0&& // we can't go round again in integer if dupcols (prob.presolveOptions_ & 0x80000000) == 0) { result = -1; // round again const CoinPresolveAction *paction = paction_; while (paction) { const CoinPresolveAction *next = paction->next; delete paction; paction = next; } paction_=NULL; } } } } else if (prob.status_ != 0) { // infeasible or unbounded result = 1 ; } } if (!result) { int nrowsAfter = presolvedModel_->getNumRows(); int ncolsAfter = presolvedModel_->getNumCols(); CoinBigIndex nelsAfter = presolvedModel_->getNumElements(); presolvedModel_->messageHandler()->message(COIN_PRESOLVE_STATS, messages) <<nrowsAfter<< -(nrows_ - nrowsAfter) << ncolsAfter<< -(ncols_ - ncolsAfter) <<nelsAfter<< -(nelems_ - nelsAfter) <<CoinMessageEol; } else { gutsOfDestroy(); delete presolvedModel_; presolvedModel_=NULL; } return presolvedModel_; }
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) ; }
/* Postsolve: replace the original row bounds. The catch here is that each constraint was an equality in the presolved problem, with a logical s<i> that had l<i> = u<i> = 0. We're about to convert the equality back to an inequality. One row bound will go to infinity, as will one of the bounds of the logical. We may need to patch the basis. The logical for a <= constraint cannot be NBUB, and the logical for a >= constraint cannot be NBLB. */ void remove_dual_action::postsolve (CoinPostsolveMatrix *prob) const { const action *const &bndRecords = actions_ ; const int &numRecs = nactions_ ; double *&rlo = prob->rlo_ ; double *&rup = prob->rup_ ; unsigned char *&rowstat = prob->rowstat_ ; # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering remove_dual_action::postsolve, " << numRecs << " bounds to restore." << std::endl ; # endif presolve_check_threads(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # endif /* For each record, restore the row bounds. If we have status arrays, check the status of the logical and adjust if necessary. In spite of the fact that the status array is an unsigned char array, we still need to use getRowStatus to make sure we're only looking at the bottom three bits. Why is this an issue? Because the status array isn't necessarily cleared to zeros, and setRowStatus carefully changes only the bottom three bits! */ for (int k = 0 ; k < numRecs ; k++) { const action &bndRec = bndRecords[k] ; const int &i = bndRec.ndx_ ; const double &rloi = bndRec.rlo_ ; const double &rupi = bndRec.rup_ ; # if PRESOLVE_DEBUG > 1 std::cout << "NDUAL(eq): row(" << i << ")" ; if (rlo[i] != rloi) std::cout << " LB " << rlo[i] << " -> " << rloi ; if (rup[i] != rupi) std::cout << " UB " << rup[i] << " -> " << rupi ; # endif rlo[i] = rloi ; rup[i] = rupi ; if (rowstat) { unsigned char stati = prob->getRowStatus(i) ; if (stati == CoinPresolveMatrix::atUpperBound) { if (rloi <= -PRESOLVE_INF) { rowstat[i] = CoinPresolveMatrix::atLowerBound ; # if PRESOLVE_DEBUG > 1 std::cout << ", status forced to " << statusName(static_cast<CoinPresolveMatrix::Status>(rowstat[i])) ; # endif } } else if (stati == CoinPresolveMatrix::atLowerBound) { if (rupi >= PRESOLVE_INF) { rowstat[i] = CoinPresolveMatrix::atUpperBound ; # if PRESOLVE_DEBUG > 1 std::cout << ", status forced to " << statusName(static_cast<CoinPresolveMatrix::Status>(rowstat[i])) ; # endif } } # if PRESOLVE_DEBUG > 2 else if (stati == CoinPresolveMatrix::basic) { std::cout << ", status is basic." ; } else if (stati == CoinPresolveMatrix::isFree) { std::cout << ", status is free?!" ; } else { unsigned int tmp = static_cast<unsigned int>(stati) ; std::cout << ", status is invalid (" << tmp << ")!" ; } # endif } # if PRESOLVE_DEBUG > 1 std::cout << "." << std::endl ; # endif } # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_threads(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving remove_dual_action::postsolve." << std::endl ; # endif # endif return ; }
/* This routine empties the columns for the list of fixed variables passed in (fcols, nfcols). As each coefficient a<ij> is set to 0, rlo<i> and rup<i> are adjusted accordingly. Note, however, that c<j> is not considered to be removed from the objective until column j is physically removed from the matrix (drop_empty_cols_action), so the correction to the objective is adjusted there. If a column solution is available, row activity (acts_) is adjusted. remove_fixed_action implicitly assumes that the value of the variable has already been forced within bounds. If this isn't true, the correction to acts_ will be wrong. See make_fixed_action if you need to force the value within bounds first. */ const remove_fixed_action* remove_fixed_action::presolve (CoinPresolveMatrix *prob, int *fcols, int nfcols, const CoinPresolveAction *next) { double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; double *rowels = prob->rowels_; int *hcol = prob->hcol_; CoinBigIndex *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; double *clo = prob->clo_; double *rlo = prob->rlo_; double *rup = prob->rup_; double *sol = prob->sol_; double *acts = prob->acts_; presolvehlink *clink = prob->clink_; presolvehlink *rlink = prob->rlink_; action *actions = new action[nfcols+1]; # if PRESOLVE_DEBUG std::cout << "Entering remove_fixed_action::presolve." << std::endl ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif /* Scan columns to be removed and total up the number of coefficients. */ int estsize=0; int ckc; for (ckc = 0 ; ckc < nfcols ; ckc++) { int j = fcols[ckc]; estsize += hincol[j]; } // Allocate arrays to hold coefficients and associated row indices double * els_action = new double[estsize]; int * rows_action = new int[estsize]; int actsize=0; // faster to do all deletes in row copy at once int nrows = prob->nrows_; CoinBigIndex * rstrt = new int[nrows+1]; CoinZeroN(rstrt,nrows); /* Open a loop to excise each column a<j>. The first thing to do is load the action entry with the index j, the value of x<j>, and the number of entries in a<j>. After we walk the column and tweak the row-major representation, we'll simply claim this column is empty by setting hincol[j] = 0. */ for (ckc = 0 ; ckc < nfcols ; ckc++) { int j = fcols[ckc]; double solj = clo[j]; CoinBigIndex kcs = mcstrt[j]; CoinBigIndex kce = kcs + hincol[j]; CoinBigIndex k; { action &f = actions[ckc]; f.col = j; f.sol = solj; f.start = actsize; } /* Now walk a<j>. For each row i with a coefficient a<ij> != 0: * save the coefficient and row index, * substitute the value of x<j>, adjusting the row bounds and lhs value accordingly, then * delete a<ij> from the row-major representation. * Finally: mark the row as changed and add it to the list of rows to be processed next. Then, for each remaining column in the row, do the same. (It makes sense to put the columns on the `to be processed' list, but I'm wondering about the wisdom of marking them as changed. -- lh, 040824 -- ) */ for (k = kcs ; k < kce ; k++) { int row = hrow[k]; double coeff = colels[k]; els_action[actsize]=coeff; rstrt[row]++; // increase counts rows_action[actsize++]=row; // Avoid reducing finite infinity. if (-PRESOLVE_INF < rlo[row]) rlo[row] -= solj*coeff; if (rup[row] < PRESOLVE_INF) rup[row] -= solj*coeff; if (sol) { acts[row] -= solj*coeff; } #define TRY2 #ifndef TRY2 presolve_delete_from_row(row,j,mrstrt,hinrow,hcol,rowels); if (hinrow[row] == 0) { PRESOLVE_REMOVE_LINK(rlink,row) ; } // mark unless already marked if (!prob->rowChanged(row)) { prob->addRow(row); CoinBigIndex krs = mrstrt[row]; CoinBigIndex kre = krs + hinrow[row]; for (CoinBigIndex k=krs; k<kre; k++) { int jcol = hcol[k]; prob->addCol(jcol); } } #endif } /* Remove the column's link from the linked list of columns, and declare it empty in the column-major representation. Link removal must execute even if the column is already of length 0 when it arrives. */ PRESOLVE_REMOVE_LINK(clink, j); hincol[j] = 0; } /* Set the actual end of the coefficient and row index arrays. */ actions[nfcols].start=actsize; # if PRESOLVE_SUMMARY printf("NFIXED: %d", nfcols); if (estsize-actsize > 0) { printf(", overalloc %d",estsize-actsize) ; } printf("\n") ; # endif // Now get columns by row int * column = new int[actsize]; int nel=0; int iRow; for (iRow=0;iRow<nrows;iRow++) { int n=rstrt[iRow]; rstrt[iRow]=nel; nel += n; } rstrt[nrows]=nel; for (ckc = 0 ; ckc < nfcols ; ckc++) { int kcs = actions[ckc].start; int j=actions[ckc].col; int kce; if (ckc<nfcols-1) kce = actions[ckc+1].start; else kce = actsize; for (int k=kcs;k<kce;k++) { int iRow = rows_action[k]; CoinBigIndex put = rstrt[iRow]; rstrt[iRow]++; column[put]=j; } } // Now do rows int ncols = prob->ncols_; char * mark = new char[ncols]; memset(mark,0,ncols); // rstrts are now one out i.e. rstrt[0] is end of row 0 nel=0; #ifdef TRY2 for (iRow=0;iRow<nrows;iRow++) { int k; for (k=nel;k<rstrt[iRow];k++) { mark[column[k]]=1; } presolve_delete_many_from_major(iRow,mark,mrstrt,hinrow,hcol,rowels); #ifndef NDEBUG for (k=nel;k<rstrt[iRow];k++) { assert(mark[column[k]]==0); } #endif if (hinrow[iRow] == 0) { PRESOLVE_REMOVE_LINK(rlink,iRow) ; } // mark unless already marked if (!prob->rowChanged(iRow)) { prob->addRow(iRow); CoinBigIndex krs = mrstrt[iRow]; CoinBigIndex kre = krs + hinrow[iRow]; for (CoinBigIndex k=krs; k<kre; k++) { int jcol = hcol[k]; prob->addCol(jcol); } } nel=rstrt[iRow]; } #endif delete [] mark; delete [] column; delete [] rstrt; # if PRESOLVE_DEBUG presolve_check_sol(prob) ; std::cout << "Leaving remove_fixed_action::presolve." << std::endl ; # endif /* Create the postsolve object, link it at the head of the list of postsolve objects, and return a pointer. */ return (new remove_fixed_action(nfcols, actions,els_action,rows_action,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) ; }
/* Transfer the cost coefficient of a column singleton in an equality to the cost coefficients of the remaining variables. Suppose x<s> is the singleton and x<t> is some other variable. For movement delta<t>, there must be compensating change delta<s> = -(a<it>/a<is>)delta<t>. Substituting in the objective, c<s>delta<s> + c<t>delta<t> becomes c<s>(-a<it>/a<is>)delta<t> + c<t>delta<t> (c<t> - c<s>(a<it>/a<is>))delta<t> This is transform (A) below. */ void transferCosts (CoinPresolveMatrix *prob) { double *colels = prob->colels_ ; int *hrow = prob->hrow_ ; CoinBigIndex *mcstrt = prob->mcstrt_ ; int *hincol = prob->hincol_ ; double *rowels = prob->rowels_ ; int *hcol = prob->hcol_ ; CoinBigIndex *mrstrt = prob->mrstrt_ ; int *hinrow = prob->hinrow_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *clo = prob->clo_ ; double *cup = prob->cup_ ; int ncols = prob->ncols_ ; double *cost = prob->cost_ ; unsigned char *integerType = prob->integerType_ ; double bias = prob->dobias_ ; # if PRESOLVE_DEBUG > 0 std::cout << "Entering transferCosts." << std::endl ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif int numberIntegers = 0 ; for (int icol = 0 ; icol < ncols ; icol++) { if (integerType[icol]) numberIntegers++ ; } /* For unfixed column singletons in equalities, calculate and install transform (A) described in the comments at the head of the method. */ int nchanged = 0 ; for (int js = 0 ; js < ncols ; js++) { if (cost[js] && hincol[js] == 1 && cup[js] > clo[js]) { const CoinBigIndex &jsstrt = mcstrt[js] ; const int &i = hrow[jsstrt]; if (rlo[i] == rup[i]) { const double ratio = cost[js]/colels[jsstrt]; bias += rlo[i]*ratio ; const CoinBigIndex &istrt = mrstrt[i] ; const CoinBigIndex iend = istrt+hinrow[i] ; for (CoinBigIndex jj = istrt ; jj < iend ; jj++) { int j = hcol[jj] ; double aij = rowels[jj] ; cost[j] -= ratio*aij ; } cost[js] = 0.0 ; nchanged++ ; } } } # if PRESOLVE_DEBUG > 0 if (nchanged) std::cout << " transferred costs for " << nchanged << " singleton columns." << std::endl ; int nPasses = 0 ; # endif /* We don't really need a singleton column to do this trick, just an equality. But if the column's not a singleton, it's only worth doing if we can move costs onto integer variables that start with costs of zero. Try and find some unfixed variable with a nonzero cost, that's involved in an equality where there are integer variables with costs of zero. If there's a net gain in the number of integer variables with costs (nThen > nNow), do the transform. One per column, please. */ if (numberIntegers) { int changed = -1 ; while (changed) { changed = 0 ; for (int js = 0 ; js < ncols ; js++) { if (cost[js] && cup[js] > clo[js]) { const CoinBigIndex &jsstrt = mcstrt[js] ; const CoinBigIndex jsend = jsstrt+hincol[js] ; for (CoinBigIndex ii = jsstrt ; ii < jsend ; ii++) { const int &i = hrow[ii] ; if (rlo[i] == rup[i]) { int nNow = ((integerType[js])?1:0) ; int nThen = 0 ; const CoinBigIndex &istrt = mrstrt[i] ; const CoinBigIndex iend = istrt+hinrow[i] ; for (CoinBigIndex jj = istrt ; jj < iend ; jj++) { int j = hcol[jj] ; if (!cost[j] && integerType[j]) nThen++ ; } if (nThen > nNow) { const double ratio = cost[js]/colels[jsstrt] ; bias += rlo[i]*ratio ; for (CoinBigIndex jj = istrt ; jj < iend ; jj++) { int j = hcol[jj] ; double aij = rowels[jj] ; cost[j] -= ratio*aij ; } cost[js] = 0.0 ; changed++ ; break ; } } } } } if (changed) { nchanged += changed ; # if PRESOLVE_DEBUG > 0 std::cout << " pass " << nPasses++ << " transferred costs to " << changed << " integer variables." << std::endl ; # endif } } } # if PRESOLVE_DEBUG > 0 if (bias != prob->dobias_) std::cout << " new bias " << bias << "." << std::endl ; # endif prob->dobias_ = bias; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving transferCosts." << std::endl ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif }
/* This routine does the actual job of fixing one or more variables. The set of indices to be fixed is specified by nfcols and fcols. fix_to_lower specifies the bound where the variable(s) should be fixed. The other bound is preserved as part of the action and the bounds are set equal. Note that you don't get to specify the bound on a per-variable basis. If a primal solution is available, make_fixed_action will adjust the the row activity to compensate for forcing the variable within bounds. If the bounds are already equal, and the variable is within bounds, you should consider remove_fixed_action. */ const CoinPresolveAction* make_fixed_action::presolve (CoinPresolveMatrix *prob, int *fcols, int nfcols, bool fix_to_lower, const CoinPresolveAction *next) { double *clo = prob->clo_; double *cup = prob->cup_; double *csol = prob->sol_; double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; double *acts = prob->acts_; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering make_fixed_action::presolve, fixed = " << nfcols << "." << std::endl ; # endif presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif /* Shouldn't happen, but ... */ if (nfcols <= 0) { # if PRESOLVE_DEBUG > 0 std::cout << "make_fixed_action::presolve: useless call, " << nfcols << " to fix." << std::endl ; # endif return (next) ; } action *actions = new action[nfcols] ; /* Scan the set of indices specifying variables to be fixed. For each variable, stash the unused bound in the action and set the bounds equal. If the client has passed in a primal solution, update it if the value of the variable changes. */ for (int ckc = 0 ; ckc < nfcols ; ckc++) { int j = fcols[ckc] ; double movement = 0 ; action &f = actions[ckc] ; f.col = j ; if (fix_to_lower) { f.bound = cup[j]; cup[j] = clo[j]; if (csol) { movement = clo[j]-csol[j] ; csol[j] = clo[j] ; } } else { f.bound = clo[j]; clo[j] = cup[j]; if (csol) { movement = cup[j]-csol[j]; csol[j] = cup[j]; } } if (movement) { CoinBigIndex k; for (k = mcstrt[j] ; k < mcstrt[j]+hincol[j] ; k++) { int row = hrow[k]; acts[row] += movement*colels[k]; } } } /* Original comment: This is unusual in that the make_fixed_action transform contains within it a remove_fixed_action transform. Bad idea? Explanatory comment: Now that we've adjusted the bounds, time to create the postsolve action that will restore the original bounds. But wait! We're not done. By calling remove_fixed_action::presolve, we will (virtually) remove these variables from the model by substituting for the variable where it occurs and emptying the column. Cache the postsolve transform that will repopulate the column inside the postsolve transform for fixing the bounds. */ if (nfcols > 0) { next = new make_fixed_action(nfcols,actions,fix_to_lower, remove_fixed_action::presolve(prob,fcols,nfcols,0), next) ; } # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving make_fixed_action::presolve." << std::endl ; # endif # endif 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); }
void do_tighten_action::postsolve(CoinPostsolveMatrix *prob) const { const action *const actions = actions_; const int nactions = nactions_; double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int *link = prob->link_; double *clo = prob->clo_; double *cup = prob->cup_; double *rlo = prob->rlo_; double *rup = prob->rup_; double *sol = prob->sol_; double *acts = prob->acts_; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 char *cdone = prob->cdone_; char *rdone = prob->rdone_; presolve_check_threads(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Entering do_tighten_action::postsolve." << std::endl ; # endif # endif for (const action *f = &actions[nactions-1]; actions<=f; f--) { int jcol = f->col; int iflag = f->direction; int nr = f->nrows; const int *rows = f->rows; const double *lbound = f->lbound; const double *ubound = f->ubound; PRESOLVEASSERT(prob->getColumnStatus(jcol)!=CoinPrePostsolveMatrix::basic); int i; for (i=0;i<nr; ++i) { int irow = rows[i]; rlo[irow] = lbound[i]; rup[irow] = ubound[i]; PRESOLVEASSERT(prob->getRowStatus(irow)==CoinPrePostsolveMatrix::basic); } // We have just tightened the row bounds. // That means we'll have to compute a new value // for this variable that will satisfy everybody. // We are supposed to be in a position where this // is always possible. // Each constraint has exactly one bound. // The correction should only ever be forced to move in one direction. // double orig_sol = sol[jcol]; double correction = 0.0; int last_corrected = -1; CoinBigIndex k = mcstrt[jcol]; int nk = hincol[jcol]; for (i=0; i<nk; ++i) { int irow = hrow[k]; double coeff = colels[k]; k = link[k]; double newrlo = rlo[irow]; double newrup = rup[irow]; double activity = acts[irow]; if (activity + correction * coeff < newrlo) { // only one of these two should fire PRESOLVEASSERT( ! (activity + correction * coeff > newrup) ); last_corrected = irow; // adjust to just meet newrlo (solve for correction) double new_correction = (newrlo - activity) / coeff; //adjust if integer if (iflag==-2||iflag==2) { new_correction += sol[jcol]; if (fabs(floor(new_correction+0.5)-new_correction)>1.0e-4) { new_correction = ceil(new_correction)-sol[jcol]; #ifdef COIN_DEVELOP printf("integer postsolve changing correction from %g to %g - flag %d\n", (newrlo-activity)/coeff,new_correction,iflag); #endif } } correction = new_correction; } else if (activity + correction * coeff > newrup) { last_corrected = irow; double new_correction = (newrup - activity) / coeff; //adjust if integer if (iflag==-2||iflag==2) { new_correction += sol[jcol]; if (fabs(floor(new_correction+0.5)-new_correction)>1.0e-4) { new_correction = ceil(new_correction)-sol[jcol]; #ifdef COIN_DEVELOP printf("integer postsolve changing correction from %g to %g - flag %d\n", (newrup-activity)/coeff,new_correction,iflag); #endif } } correction = new_correction; } } if (last_corrected>=0) { sol[jcol] += correction; // by construction, the last row corrected (if there was one) // must be at its bound, so it can be non-basic. // All other rows may not be at a bound (but may if the difference // is very small, causing a new correction by a tiny amount). // now adjust the activities k = mcstrt[jcol]; for (i=0; i<nk; ++i) { int irow = hrow[k]; double coeff = colels[k]; k = link[k]; // double activity = acts[irow]; acts[irow] += correction * coeff; } /* If the col happens to get pushed to its bound, we may as well leave it non-basic. Otherwise, set the status to basic. Why do we correct the row status only when the column is made basic? Need to look at preceding code. -- lh, 110528 -- */ if (fabs(sol[jcol]-clo[jcol]) > ZTOLDP && fabs(sol[jcol]-cup[jcol]) > ZTOLDP) { prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic); if (acts[last_corrected]-rlo[last_corrected] < rup[last_corrected]-acts[last_corrected]) prob->setRowStatus(last_corrected, CoinPrePostsolveMatrix::atUpperBound); else prob->setRowStatus(last_corrected, CoinPrePostsolveMatrix::atLowerBound); } } } # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_threads(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving do_tighten_action::postsolve." << std::endl ; # endif # endif }
/* Undo the substitutions from presolve and reintroduce the target constraint and column. */ void subst_constraint_action::postsolve(CoinPostsolveMatrix *prob) const { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering subst_constraint_action::postsolve, " << nactions_ << " constraints to process." << std::endl ; # endif int ncols = prob->ncols_ ; char *cdone = prob->cdone_ ; char *rdone = prob->rdone_ ; const double ztolzb = prob->ztolzb_ ; presolve_check_threads(prob) ; presolve_check_free_list(prob) ; presolve_check_reduced_costs(prob) ; presolve_check_duals(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # endif /* Unpack the column-major representation. */ CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; int *rowIndices = prob->hrow_ ; double *colCoeffs = prob->colels_ ; /* Rim vectors, solution, reduced costs, duals, row activity. */ double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *cost = prob->cost_ ; double *sol = prob->sol_ ; double *rcosts = prob->rcosts_ ; double *acts = prob->acts_ ; double *rowduals = prob->rowduals_ ; CoinBigIndex *link = prob->link_ ; CoinBigIndex &free_list = prob->free_list_ ; const double maxmin = prob->maxmin_ ; const action *const actions = actions_ ; const int nactions = nactions_ ; /* Open the main loop to step through the postsolve objects. First activity is to unpack the postsolve object. We have the target column and row indices, the full target column, and complete copies of all entangled rows (column indices, coefficients, lower and upper bounds). There may be a vector of objective coefficients which we'll get to later. */ for (const action *f = &actions[nactions-1] ; actions <= f ; f--) { const int tgtcol = f->col ; const int tgtrow = f->rowy ; const int tgtcol_len = f->nincol ; const double *tgtcol_coeffs = f->coeffxs ; const int *entngld_rows = f->rows ; const int *entngld_lens = f->ninrowxs ; const int *entngld_colndxs = f->rowcolsxs ; const double *entngld_colcoeffs = f->rowelsxs ; const double *entngld_rlos = f->rlos ; const double *entngld_rups = f->rups ; const double *costs = f->costsx ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 1 std::cout << " reintroducing column x(" << tgtcol << ") and row " << tgtrow ; if (costs) std::cout << ", nonzero costs" ; std::cout << "." << std::endl ; # endif /* We're about to reintroduce the target row and column; empty stubs should be present. All other rows should already be present. */ PRESOLVEASSERT(cdone[tgtcol] == DROP_COL) ; PRESOLVEASSERT(colLengths[tgtcol] == 0) ; PRESOLVEASSERT(rdone[tgtrow] == DROP_ROW) ; for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) { if (entngld_rows[cndx] != tgtrow) PRESOLVEASSERT(rdone[entngld_rows[cndx]]) ; } /* In a postsolve matrix, we can't just check that the length of the row is zero. We need to look at all columns and confirm its absence. */ for (int j = 0 ; j < ncols ; ++j) { if (colLengths[j] > 0 && cdone[j]) { const CoinBigIndex kcs = colStarts[j] ; const int lenj = colLengths[j] ; CoinBigIndex krow = presolve_find_row3(tgtrow,kcs,lenj,rowIndices,link) ; if (krow >= 0) { std::cout << " BAD COEFF! row " << tgtrow << " present in column " << j << " before reintroduction; a(" << tgtrow << "," << j << ") = " << colCoeffs[krow] << "; x(" << j << ") = " << sol[j] << "; cdone " << static_cast<int>(cdone[j]) << "." << std::endl ; } } } # endif /* Find the copy of the target row. Restore the upper and lower bounds of entangled rows while we're looking. Recall that the target row is an equality. */ int tgtrow_len = -1 ; const int *tgtrow_colndxs = NULL ; const double *tgtrow_coeffs = NULL ; double tgtcoeff = 0.0 ; double tgtrhs = 1.0e50 ; int nel = 0 ; for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) { int i = entngld_rows[cndx] ; rlo[i] = entngld_rlos[cndx] ; rup[i] = entngld_rups[cndx] ; if (i == tgtrow) { tgtrow_len = entngld_lens[cndx] ; tgtrow_colndxs = &entngld_colndxs[nel] ; tgtrow_coeffs = &entngld_colcoeffs[nel] ; tgtcoeff = tgtcol_coeffs[cndx] ; tgtrhs = rlo[i] ; } nel += entngld_lens[cndx] ; } /* Solve the target equality to find the solution for the eliminated col. tgtcol is present in tgtrow_colndxs, so initialise sol[tgtcol] to zero to make sure it doesn't contribute. If we're debugging, check that the result is within bounds. */ double tgtexp = tgtrhs ; sol[tgtcol] = 0.0 ; for (int ndx = 0 ; ndx < tgtrow_len ; ++ndx) { int j = tgtrow_colndxs[ndx] ; double coeffj = tgtrow_coeffs[ndx] ; tgtexp -= coeffj*sol[j] ; } sol[tgtcol] = tgtexp/tgtcoeff ; # if PRESOLVE_DEBUG > 0 double *clo = prob->clo_ ; double *cup = prob->cup_ ; if (!(sol[tgtcol] > (clo[tgtcol]-ztolzb) && (cup[tgtcol]+ztolzb) > sol[tgtcol])) { std::cout << "BAD SOL: x(" << tgtcol << ") " << sol[tgtcol] << "; lb " << clo[tgtcol] << "; ub " << cup[tgtcol] << "." << std::endl ; } # endif /* Now restore the original entangled rows. We first delete any columns present in tgtrow. This will remove any fillin, but may also remove columns that were originally present in both the entangled row and the target row. Note that even cancellations (explicit zeros) are present at this point --- in presolve, they were removed after the substition transform completed, hence they're already restored. What isn't present is the target column, which is deleted as part of the transform. */ { # if PRESOLVE_DEBUG > 2 std::cout << " removing coefficients:" ; # endif for (int rndx = 0 ; rndx < tgtrow_len ; ++rndx) { int j = tgtrow_colndxs[rndx] ; if (j != tgtcol) for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) { if (entngld_rows[cndx] != tgtrow) { # if PRESOLVE_DEBUG > 2 std::cout << " a(" << entngld_rows[cndx] << "," << j << ")" ; # endif presolve_delete_from_col2(entngld_rows[cndx],j,colStarts, colLengths,rowIndices,link,&free_list) ; } } } # if PRESOLVE_DEBUG > 2 std::cout << std::endl ; # endif # if PRESOLVE_CONSISTENCY > 0 presolve_check_threads(prob) ; presolve_check_free_list(prob) ; # endif /* Next we restore the original coefficients. The outer loop walks tgtcol; cols_i and coeffs_i are advanced as we go to point to each entangled row. The inner loop walks the entangled row and restores the row's coefficients. Tgtcol is handled as any other column. Skip tgtrow, we'll do it below. Since we don't have a row-major representation, we have to look for a(i,j) from entangled row i in the existing column j. If we find a(i,j), simply update it (and a(tgtrow,j) should not exist). If we don't find a(i,j), introduce it (and a(tgtrow,j) should exist). Recalculate the row activity while we're at it. */ # if PRESOLVE_DEBUG > 2 std::cout << " restoring coefficients:" ; # endif colLengths[tgtcol] = 0 ; const int *cols_i = entngld_colndxs ; const double *coeffs_i = entngld_colcoeffs ; for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) { const int leni = entngld_lens[cndx] ; const int i = entngld_rows[cndx] ; if (i != tgtrow) { double acti = 0.0 ; for (int rndx = 0 ; rndx < leni ; ++rndx) { const int j = cols_i[rndx] ; CoinBigIndex kcoli = presolve_find_row3(i,colStarts[j], colLengths[j],rowIndices,link) ; if (kcoli != -1) { # if PRESOLVE_DEBUG > 2 std::cout << " u a(" << i << "," << j << ")" ; PRESOLVEASSERT(presolve_find_col1(j,0,tgtrow_len, tgtrow_colndxs) == tgtrow_len) ; # endif colCoeffs[kcoli] = coeffs_i[rndx] ; } else { # if PRESOLVE_DEBUG > 2 std::cout << " f a(" << i << "," << j << ")" ; PRESOLVEASSERT(presolve_find_col1(j,0,tgtrow_len, tgtrow_colndxs) < tgtrow_len) ; # endif CoinBigIndex kk = free_list ; assert(kk >= 0 && kk < prob->bulk0_) ; free_list = link[free_list] ; link[kk] = colStarts[j] ; colStarts[j] = kk ; colCoeffs[kk] = coeffs_i[rndx] ; rowIndices[kk] = i ; ++colLengths[j] ; } acti += coeffs_i[rndx]*sol[j] ; } acts[i] = acti ; } cols_i += leni ; coeffs_i += leni ; } # if PRESOLVE_DEBUG > 2 std::cout << std::endl ; # endif # if PRESOLVE_CONSISTENCY > 0 presolve_check_threads(prob) ; presolve_check_free_list(prob) ; # endif /* Restore tgtrow. Arguably we could to this in the previous loop, but we'd do a lot of unnecessary work. By construction, the target row is tight. */ # if PRESOLVE_DEBUG > 2 std::cout << " restoring row " << tgtrow << ":" ; # endif for (int rndx = 0 ; rndx < tgtrow_len ; ++rndx) { int j = tgtrow_colndxs[rndx] ; # if PRESOLVE_DEBUG > 2 std::cout << " a(" << tgtrow << "," << j << ")" ; # endif CoinBigIndex kk = free_list ; assert(kk >= 0 && kk < prob->bulk0_) ; free_list = link[free_list] ; link[kk] = colStarts[j] ; colStarts[j] = kk ; colCoeffs[kk] = tgtrow_coeffs[rndx] ; rowIndices[kk] = tgtrow ; ++colLengths[j] ; } acts[tgtrow] = tgtrhs ; # if PRESOLVE_DEBUG > 2 std::cout << std::endl ; # endif # if PRESOLVE_CONSISTENCY > 0 presolve_check_threads(prob) ; presolve_check_free_list(prob) ; # endif } /* Restore original cost coefficients, if necessary. */ if (costs) { for (int ndx = 0 ; ndx < tgtrow_len ; ++ndx) { cost[tgtrow_colndxs[ndx]] = costs[ndx] ; } } /* Calculate the reduced cost for the column absent any contribution from tgtrow, then set the dual for tgtrow so that the reduced cost of tgtcol is zero. */ double dj = maxmin*cost[tgtcol] ; rowduals[tgtrow] = 0.0 ; for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) { int i = entngld_rows[cndx] ; double coeff = tgtcol_coeffs[cndx] ; dj -= rowduals[i]*coeff ; } rowduals[tgtrow] = dj/tgtcoeff ; rcosts[tgtcol] = 0.0 ; if (rowduals[tgtrow] > 0) prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atUpperBound) ; else prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atLowerBound) ; prob->setColumnStatus(tgtcol,CoinPrePostsolveMatrix::basic) ; # if PRESOLVE_DEBUG > 2 std::cout << " row " << tgtrow << " " << prob->rowStatusString(prob->getRowStatus(tgtrow)) << " dual " << rowduals[tgtrow] << std::endl ; std::cout << " col " << tgtcol << " " << prob->columnStatusString(prob->getColumnStatus(tgtcol)) << " dj " << dj << std::endl ; # endif # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 cdone[tgtcol] = SUBST_ROW ; rdone[tgtrow] = SUBST_ROW ; # endif } # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_threads(prob) ; presolve_check_free_list(prob) ; presolve_check_reduced_costs(prob) ; presolve_check_duals(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving subst_constraint_action::postsolve." << std::endl ; # endif # endif return ; }
/* 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); }
/* * Say we determined that cup - clo <= ztolzb, so we fixed sol at clo. * This involved subtracting clo*coeff from ub/lb for each row the * variable occurred in. * Now when we put the variable back in, by construction the variable * is within tolerance, the non-slacks are unchanged, and the * distances of the affected slacks from their bounds should remain * unchanged (ignoring roundoff errors). * It may be that by adding the term back in, the affected constraints * now aren't as accurate due to round-off errors; this could happen * if only one summand and the slack in the original formulation were large * (and naturally had opposite signs), and the new term in the constraint * is about the size of the old slack, so the new slack becomes about 0. * It may be that there is catastrophic cancellation in the summation, * so it might not compute to 0. */ void remove_fixed_action::postsolve(CoinPostsolveMatrix *prob) const { action * actions = actions_; const int nactions = nactions_; double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int *link = prob->link_; CoinBigIndex &free_list = prob->free_list_; double *clo = prob->clo_; double *cup = prob->cup_; double *rlo = prob->rlo_; double *rup = prob->rup_; double *sol = prob->sol_; double *dcost = prob->cost_; double *rcosts = prob->rcosts_; double *acts = prob->acts_; double *rowduals = prob->rowduals_; unsigned char *colstat = prob->colstat_; const double maxmin = prob->maxmin_; # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY char *cdone = prob->cdone_; std::cout << "Entering remove_fixed_action::postsolve." << std::endl ; presolve_check_threads(prob) ; presolve_check_free_list(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif double * els_action = colels_; int * rows_action = colrows_; int end = actions[nactions].start; /* At one point, it turned out that forcing_constraint_action was putting duplicates in the column list it passed to remove_fixed_action. This is now fixed, but ... it looks to me like we could be in trouble here if we reinstate a column multiple times. Hence the assert. */ for (const action *f = &actions[nactions-1]; actions<=f; f--) { int icol = f->col; const double thesol = f->sol; # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY assert(cdone[icol] != FIXED_VARIABLE) ; cdone[icol] = FIXED_VARIABLE ; # endif sol[icol] = thesol; clo[icol] = thesol; cup[icol] = thesol; int cs = NO_LINK ; int start = f->start; double dj = maxmin * dcost[icol]; for (int i=start; i<end; ++i) { int row = rows_action[i]; double coeff =els_action[i]; // pop free_list CoinBigIndex k = free_list; assert(k >= 0 && k < prob->bulk0_) ; free_list = link[free_list]; // restore hrow[k] = row; colels[k] = coeff; link[k] = cs; cs = k; if (-PRESOLVE_INF < rlo[row]) rlo[row] += coeff * thesol; if (rup[row] < PRESOLVE_INF) rup[row] += coeff * thesol; acts[row] += coeff * thesol; dj -= rowduals[row] * coeff; } # if PRESOLVE_CONSISTENCY presolve_check_free_list(prob) ; # endif mcstrt[icol] = cs; rcosts[icol] = dj; hincol[icol] = end-start; end=start; /* Original comment: * the bounds in the reduced problem were tightened. * that means that this variable may not have been basic * because it didn't have to be, * but now it may have to. * no - the bounds aren't changed by this operation */ /* We've reintroduced the variable, but it's still fixed (equal bounds). Pick the nonbasic status that agrees with the reduced cost. Later, if postsolve unfixes the variable, we'll need to confirm that this status is still viable. We live in a minimisation world here. */ if (colstat) { if (dj < 0) prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atUpperBound); else prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atLowerBound); } } # if PRESOLVE_CONSISTENCY || PRESOLVE_DEBUG presolve_check_threads(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; std::cout << "Leaving remove_fixed_action::postsolve." << std::endl ; # endif return ; }
/* Reintroduce the column (y) and doubleton row (irow) removed in presolve. Correct the other column (x) involved in the doubleton, update the solution, etc. A fair amount of complication arises because the presolve transform saves the shorter of x or y. Postsolve thus includes portions to restore either. */ void doubleton_action::postsolve(CoinPostsolveMatrix *prob) const { const action *const actions = actions_ ; const int nactions = nactions_ ; double *colels = prob->colels_ ; int *hrow = prob->hrow_ ; CoinBigIndex *mcstrt = prob->mcstrt_ ; int *hincol = prob->hincol_ ; int *link = prob->link_ ; double *clo = prob->clo_ ; double *cup = prob->cup_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *dcost = prob->cost_ ; double *sol = prob->sol_ ; double *acts = prob->acts_ ; double *rowduals = prob->rowduals_ ; double *rcosts = prob->rcosts_ ; unsigned char *colstat = prob->colstat_ ; unsigned char *rowstat = prob->rowstat_ ; const double maxmin = prob->maxmin_ ; CoinBigIndex &free_list = prob->free_list_ ; const double ztolzb = prob->ztolzb_ ; const double ztoldj = prob->ztoldj_ ; const double ztolzero = 1.0e-12 ; int nrows = prob->nrows_ ; // Arrays to rebuild the unsaved column. int *index1 = new int[nrows] ; double *element1 = new double[nrows] ; CoinZeroN(element1,nrows) ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 char *cdone = prob->cdone_ ; char *rdone = prob->rdone_ ; presolve_check_threads(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; presolve_check_reduced_costs(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Entering doubleton_action::postsolve, " << nactions << " transforms to undo." << std::endl ; # endif # endif /* The outer loop: step through the doubletons in this array of actions. The first activity is to unpack the doubleton. */ for (const action *f = &actions[nactions-1] ; actions <= f ; f--) { const int irow = f->row ; const double lo0 = f->clox ; const double up0 = f->cupx ; const double coeffx = f->coeffx ; const double coeffy = f->coeffy ; const int jcolx = f->icolx ; const int jcoly = f->icoly ; const double rhs = f->rlo ; # if PRESOLVE_DEBUG > 2 std::cout << std::endl << " restoring doubleton " << irow << ", elim x(" << jcoly << "), kept x(" << jcolx << "); stored col " ; if (f->ncoly) std::cout << jcoly ; else std::cout << jcolx ; std::cout << "." << std::endl ; std::cout << " x(" << jcolx << ") " << prob->columnStatusString(jcolx) << " " << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx] << "; cj " << f->costx << " dj " << rcosts[jcolx] << "." << std::endl ; # endif /* jcolx is in the problem (for whatever reason), and the doubleton row (irow) and column (jcoly) have only been processed by empty row/column postsolve (i.e., reintroduced with length 0). */ PRESOLVEASSERT(cdone[jcolx] && rdone[irow] == DROP_ROW) ; PRESOLVEASSERT(cdone[jcoly] == DROP_COL) ; /* Restore bounds for doubleton row, bounds and objective coefficient for x, objective for y. Original comment: restoration of rlo and rup likely isn't necessary. */ rlo[irow] = f->rlo ; rup[irow] = f->rlo ; clo[jcolx] = lo0 ; cup[jcolx] = up0 ; dcost[jcolx] = f->costx ; dcost[jcoly] = f->costy ; /* Set primal solution for y (including status) and row activity for the doubleton row. The motivation (up in presolve) for wanting coeffx < coeffy is to avoid inflation into sol[y]. Since this is a (satisfied) equality, activity is the rhs value and the logical is nonbasic. */ const double diffy = rhs-coeffx*sol[jcolx] ; if (fabs(diffy) < ztolzero) sol[jcoly] = 0 ; else sol[jcoly] = diffy/coeffy ; acts[irow] = rhs ; if (rowstat) prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound) ; # if PRESOLVE_DEBUG > 2 /* Original comment: I've forgotten what this is about We have sol[y] = (rhs - coeffx*sol[x])/coeffy. As best I can figure, the original check here tested for the possibility of loss of significant digits through cancellation, followed by inflation if coeffy is small. The hazard is clear enough, but the test was puzzling. Overly complicated and it generated false warnings for the common case of sol[y] a clean zero. Replaced with something that I hope is more useful. The tolerances are, sad to say, completely arbitrary. -- lh, 121106 -- */ if ((fabs(diffy) < 1.0e-6) && (fabs(diffy) >= ztolzero) && (fabs(coeffy) < 1.0e-3)) std::cout << " loss of significance? rhs " << rhs << " (coeffx*sol[jcolx])" << (coeffx*sol[jcolx]) << " diff " << diffy << "." << std::endl ; # endif /* Time to get into the correction/restoration of coefficients for columns x and y, with attendant correction of row bounds and activities. Accumulate partial reduced costs (missing the contribution from the doubleton row) so that we can eventually calculate a dual for the doubleton row. */ double djy = maxmin*dcost[jcoly] ; double djx = maxmin*dcost[jcolx] ; /* We saved column y in the action, so we'll use it to reconstruct column x. There are two aspects: correction of existing x coefficients, and fill in. Given coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor we have coeffx[k] = coeffx'[k]-coeffy[k]*coeff_factor where coeff_factor = -coeffx[dblton]/coeffy[dblton]. Keep in mind that the major vector stored in the action does not include the coefficient from the doubleton row --- the doubleton coefficients are held in coeffx and coeffy. */ if (f->ncoly) { int ncoly = f->ncoly-1 ; int *indy = reinterpret_cast<int *>(f->colel+ncoly) ; /* Rebuild a threaded column y, starting with the end of the thread and working back to the beginning. In the process, accumulate corrections to column x in element1 and index1. Fix row bounds and activity as we go (add back the constant correction removed in presolve), and accumulate contributions to the reduced cost for y. Don't tweak finite infinity. The PRESOLVEASSERT says this row should already be present. */ int ystart = NO_LINK ; int nX = 0 ; for (int kcol = 0 ; kcol < ncoly ; ++kcol) { const int i = indy[kcol] ; PRESOLVEASSERT(rdone[i]) ; double yValue = f->colel[kcol] ; if (-PRESOLVE_INF < rlo[i]) rlo[i] += (yValue*rhs)/coeffy ; if (rup[i] < PRESOLVE_INF) rup[i] += (yValue*rhs)/coeffy ; acts[i] += (yValue*rhs)/coeffy ; djy -= rowduals[i]*yValue ; /* Link the coefficient into column y: Acquire the first free slot in the bulk arrays and store the row index and coefficient. Then link the slot in front of coefficients we've already processed. */ const CoinBigIndex kfree = free_list ; assert(kfree >= 0 && kfree < prob->bulk0_) ; free_list = link[free_list] ; hrow[kfree] = i ; colels[kfree] = yValue ; link[kfree] = ystart ; ystart = kfree ; # if PRESOLVE_DEBUG > 4 std::cout << " link y " << kfree << " row " << i << " coeff " << yValue << " dual " << rowduals[i] << std::endl ; # endif /* Calculate and store the correction to the x coefficient. */ yValue = (yValue*coeffx)/coeffy ; element1[i] = yValue ; index1[nX++] = i ; } # if PRESOLVE_CONSISTENCY > 0 presolve_check_free_list(prob) ; # endif /* Handle the coefficients of the doubleton row. Insert coeffy, coeffx. */ const CoinBigIndex kfree = free_list ; assert(kfree >= 0 && kfree < prob->bulk0_) ; free_list = link[free_list] ; hrow[kfree] = irow ; colels[kfree] = coeffy ; link[kfree] = ystart ; ystart = kfree ; # if PRESOLVE_DEBUG > 4 std::cout << " link y " << kfree << " row " << irow << " coeff " << coeffy << " dual n/a" << std::endl ; # endif element1[irow] = coeffx ; index1[nX++] = irow ; /* Attach the threaded column y to mcstrt and record the length. */ mcstrt[jcoly] = ystart ; hincol[jcoly] = f->ncoly ; /* Now integrate the corrections to column x. Scan the column and correct the existing entries. The correction could cancel the existing coefficient and we don't want to leave an explicit zero. In this case, relink the column around it. The freed slot is linked at the beginning of the free list. */ CoinBigIndex kcs = mcstrt[jcolx] ; CoinBigIndex last_nonzero = NO_LINK ; int numberInColumn = hincol[jcolx] ; const int numberToDo = numberInColumn ; for (int kcol = 0 ; kcol < numberToDo ; ++kcol) { const int i = hrow[kcs] ; assert(i >= 0 && i < nrows && i != irow) ; double value = colels[kcs]+element1[i] ; element1[i] = 0.0 ; if (fabs(value) >= 1.0e-15) { colels[kcs] = value ; last_nonzero = kcs ; kcs = link[kcs] ; djx -= rowduals[i]*value ; # if PRESOLVE_DEBUG > 4 std::cout << " link x " << last_nonzero << " row " << i << " coeff " << value << " dual " << rowduals[i] << std::endl ; # endif } else { # if PRESOLVE_DEBUG > 4 std::cout << " link x skipped row " << i << " dual " << rowduals[i] << std::endl ; # endif numberInColumn-- ; // add to free list int nextk = link[kcs] ; assert(free_list >= 0) ; link[kcs] = free_list ; free_list = kcs ; assert(kcs >= 0) ; kcs = nextk ; if (last_nonzero != NO_LINK) link[last_nonzero] = kcs ; else mcstrt[jcolx] = kcs ; } } if (last_nonzero != NO_LINK) link[last_nonzero] = NO_LINK ; /* We've dealt with the existing nonzeros in column x. Any remaining nonzeros in element1 will be fill in, which we insert at the beginning of the column. */ for (int kcol = 0 ; kcol < nX ; kcol++) { const int i = index1[kcol] ; double xValue = element1[i] ; element1[i] = 0.0 ; if (fabs(xValue) >= 1.0e-15) { if (i != irow) djx -= rowduals[i]*xValue ; numberInColumn++ ; CoinBigIndex kfree = free_list ; assert(kfree >= 0 && kfree < prob->bulk0_) ; free_list = link[free_list] ; hrow[kfree] = i ; PRESOLVEASSERT(rdone[hrow[kfree]] || (hrow[kfree] == irow)) ; colels[kfree] = xValue ; link[kfree] = mcstrt[jcolx] ; mcstrt[jcolx] = kfree ; # if PRESOLVE_DEBUG > 4 std::cout << " link x " << kfree << " row " << i << " coeff " << xValue << " dual " ; if (i != irow) std::cout << rowduals[i] ; else std::cout << "n/a" ; std::cout << std::endl ; # endif } } # if PRESOLVE_CONSISTENCY > 0 presolve_check_free_list(prob) ; # endif /* Whew! Set the column length and we're done. */ assert(numberInColumn) ; hincol[jcolx] = numberInColumn ; } else { /* Of course, we could have saved column x in the action. Now we need to regenerate coefficients of column y. Given coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor we have coeffy[k] = (coeffx'[k]-coeffx[k])*(1/coeff_factor) where coeff_factor = -coeffx[dblton]/coeffy[dblton]. */ const int ncolx = f->ncolx-1 ; int *indx = reinterpret_cast<int *> (f->colel+ncolx) ; /* Scan existing column x to find the end. While we're at it, accumulate part of the new y coefficients in index1 and element1. */ CoinBigIndex kcs = mcstrt[jcolx] ; int nX = 0 ; for (int kcol = 0 ; kcol < hincol[jcolx]-1 ; ++kcol) { if (colels[kcs]) { const int i = hrow[kcs] ; index1[nX++] = i ; element1[i] = -(colels[kcs]*coeffy)/coeffx ; } kcs = link[kcs] ; } if (colels[kcs]) { const int i = hrow[kcs] ; index1[nX++] = i ; element1[i] = -(colels[kcs]*coeffy)/coeffx ; } /* Replace column x with the the original column x held in the doubleton action (recall that this column does not include coeffx). We first move column x to the free list, then thread a column with the original coefficients, back to front. While we're at it, add the second part of the y coefficients to index1 and element1. */ link[kcs] = free_list ; free_list = mcstrt[jcolx] ; int xstart = NO_LINK ; for (int kcol = 0 ; kcol < ncolx ; ++kcol) { const int i = indx[kcol] ; PRESOLVEASSERT(rdone[i] && i != irow) ; double xValue = f->colel[kcol] ; CoinBigIndex k = free_list ; assert(k >= 0 && k < prob->bulk0_) ; free_list = link[free_list] ; hrow[k] = i ; colels[k] = xValue ; link[k] = xstart ; xstart = k ; djx -= rowduals[i]*xValue ; xValue = (xValue*coeffy)/coeffx ; if (!element1[i]) { element1[i] = xValue ; index1[nX++] = i ; } else { element1[i] += xValue ; } } # if PRESOLVE_CONSISTENCY > 0 presolve_check_free_list(prob) ; # endif /* The same, for the doubleton row. */ { double xValue = coeffx ; CoinBigIndex k = free_list ; assert(k >= 0 && k < prob->bulk0_) ; free_list = link[free_list] ; hrow[k] = irow ; colels[k] = xValue ; link[k] = xstart ; xstart = k ; element1[irow] = coeffy ; index1[nX++] = irow ; } /* Link the new column x to mcstrt and set the length. */ mcstrt[jcolx] = xstart ; hincol[jcolx] = f->ncolx ; /* Now get to work building a threaded column y from the nonzeros in element1. As before, build the thread in reverse. */ int ystart = NO_LINK ; int leny = 0 ; for (int kcol = 0 ; kcol < nX ; kcol++) { const int i = index1[kcol] ; PRESOLVEASSERT(rdone[i] || i == irow) ; double yValue = element1[i] ; element1[i] = 0.0 ; if (fabs(yValue) >= ztolzero) { leny++ ; CoinBigIndex k = free_list ; assert(k >= 0 && k < prob->bulk0_) ; free_list = link[free_list] ; hrow[k] = i ; colels[k] = yValue ; link[k] = ystart ; ystart = k ; } } # if PRESOLVE_CONSISTENCY > 0 presolve_check_free_list(prob) ; # endif /* Tidy up --- link the new column into mcstrt and set the length. */ mcstrt[jcoly] = ystart ; assert(leny) ; hincol[jcoly] = leny ; /* Now that we have the original y, we can scan it and do the corrections to the row bounds and activity, and get a start on a reduced cost for y. */ kcs = mcstrt[jcoly] ; const int ny = hincol[jcoly] ; for (int kcol = 0 ; kcol < ny ; ++kcol) { const int row = hrow[kcs] ; const double coeff = colels[kcs] ; kcs = link[kcs] ; if (row != irow) { // undo elim_doubleton(1) if (-PRESOLVE_INF < rlo[row]) rlo[row] += (coeff*rhs)/coeffy ; // undo elim_doubleton(2) if (rup[row] < PRESOLVE_INF) rup[row] += (coeff*rhs)/coeffy ; acts[row] += (coeff*rhs)/coeffy ; djy -= rowduals[row]*coeff ; } } } # if PRESOLVE_DEBUG > 2 /* Sanity checks. The doubleton coefficients should be linked in the first position of the each column (for no good reason except that it makes it much easier to write these checks). */ # if PRESOLVE_DEBUG > 4 std::cout << " kept: saved " << jcolx << " " << coeffx << ", reconstructed " << hrow[mcstrt[jcolx]] << " " << colels[mcstrt[jcolx]] << "." << std::endl ; std::cout << " elim: saved " << jcoly << " " << coeffy << ", reconstructed " << hrow[mcstrt[jcoly]] << " " << colels[mcstrt[jcoly]] << "." << std::endl ; # endif assert((coeffx == colels[mcstrt[jcolx]]) && (coeffy == colels[mcstrt[jcoly]])) ; # endif /* Time to calculate a dual for the doubleton row, and settle the status of x and y. Ideally, we'll leave x at whatever nonbasic status it currently has and make y basic. There's a potential problem, however: Remember that we transferred bounds from y to x when we eliminated y. If those bounds were tighter than x's original bounds, we may not be able to maintain x at its present status, or even as nonbasic. We'll make two claims here: * If the dual value for the doubleton row is chosen to keep the reduced cost djx of col x at its prior value, then the reduced cost djy of col y will be 0. (Crank through the linear algebra to convince yourself.) * If the bounds on x have loosened, then it must be possible to make y nonbasic, because we've transferred the tight bound back to y. (Yeah, I'm waving my hands. But it sounds good. -- lh, 040907 --) So ... if we can maintain x nonbasic, then we need to set y basic, which means we should calculate rowduals[dblton] so that rcost[jcoly] == 0. We may need to change the status of x (an artifact of loosening a bound when x was previously a fixed variable). If we need to push x into the basis, then we calculate rowduals[dblton] so that rcost[jcolx] == 0 and make y nonbasic. */ # if PRESOLVE_DEBUG > 2 std::cout << " pre status: x(" << jcolx << ") " << prob->columnStatusString(jcolx) << " " << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx] << ", cj " << dcost[jcolx] << ", dj " << djx << "." << std::endl ; std::cout << " pre status: x(" << jcoly << ") " << clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly] << ", cj " << dcost[jcoly] << ", dj " << djy << "." << std::endl ; # endif if (colstat) { bool basicx = prob->columnIsBasic(jcolx) ; bool nblbxok = (fabs(lo0 - sol[jcolx]) < ztolzb) && (rcosts[jcolx] >= -ztoldj) ; bool nbubxok = (fabs(up0 - sol[jcolx]) < ztolzb) && (rcosts[jcolx] <= ztoldj) ; if (basicx || nblbxok || nbubxok) { if (!basicx) { if (nblbxok) { prob->setColumnStatus(jcolx, CoinPrePostsolveMatrix::atLowerBound) ; } else if (nbubxok) { prob->setColumnStatus(jcolx, CoinPrePostsolveMatrix::atUpperBound) ; } } prob->setColumnStatus(jcoly,CoinPrePostsolveMatrix::basic) ; rowduals[irow] = djy/coeffy ; rcosts[jcolx] = djx-rowduals[irow]*coeffx ; rcosts[jcoly] = 0.0 ; } else { prob->setColumnStatus(jcolx,CoinPrePostsolveMatrix::basic) ; prob->setColumnStatusUsingValue(jcoly) ; rowduals[irow] = djx/coeffx ; rcosts[jcoly] = djy-rowduals[irow]*coeffy ; rcosts[jcolx] = 0.0 ; } # if PRESOLVE_DEBUG > 2 std::cout << " post status: " << irow << " dual " << rowduals[irow] << " rhs " << rlo[irow] << std::endl ; std::cout << " post status: x(" << jcolx << ") " << prob->columnStatusString(jcolx) << " " << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx] << ", cj " << dcost[jcolx] << ", dj = " << rcosts[jcolx] << "." << std::endl ; std::cout << " post status: x(" << jcoly << ") " << prob->columnStatusString(jcoly) << " " << clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly] << ", cj " << dcost[jcoly] << ", dj " << rcosts[jcoly] << "." << std::endl ; /* These asserts are valid but need a scaled tolerance to work well over a range of problems. Occasionally useful for a hard stop while debugging. assert(!prob->columnIsBasic(jcolx) || (fabs(rcosts[jcolx]) < 1.0e-5)) ; assert(!prob->columnIsBasic(jcoly) || (fabs(rcosts[jcoly]) < 1.0e-5)) ; */ # endif } else { // No status array // this is the coefficient we need to force col y's reduced cost to 0.0 ; // for example, this is obviously true if y is a singleton column rowduals[irow] = djy/coeffy ; rcosts[jcoly] = 0.0 ; } # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 /* Mark the column and row as processed by doubleton action. Then check integrity of the threaded matrix. */ cdone[jcoly] = DOUBLETON ; rdone[irow] = DOUBLETON ; presolve_check_threads(prob) ; # endif # if PRESOLVE_DEBUG > 0 /* Confirm accuracy of reduced cost for columns x and y. */ { CoinBigIndex k = mcstrt[jcolx] ; const int nx = hincol[jcolx] ; double dj = maxmin*dcost[jcolx] ; for (int kcol = 0 ; kcol < nx ; ++kcol) { const int row = hrow[k] ; const double coeff = colels[k] ; k = link[k] ; dj -= rowduals[row]*coeff ; } if (!(fabs(rcosts[jcolx]-dj) < 100*ZTOLDP)) printf("BAD DOUBLE X DJ: %d %d %g %g\n", irow,jcolx,rcosts[jcolx],dj) ; rcosts[jcolx] = dj ; } { CoinBigIndex k = mcstrt[jcoly] ; const int ny = hincol[jcoly] ; double dj = maxmin*dcost[jcoly] ; for (int kcol = 0 ; kcol < ny ; ++kcol) { const int row = hrow[k] ; const double coeff = colels[k] ; k = link[k] ; dj -= rowduals[row]*coeff ; } if (!(fabs(rcosts[jcoly]-dj) < 100*ZTOLDP)) printf("BAD DOUBLE Y DJ: %d %d %g %g\n", irow,jcoly,rcosts[jcoly],dj) ; rcosts[jcoly] = dj ; } # endif } /* Done at last. Delete the scratch arrays. */ delete [] index1 ; delete [] element1 ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; presolve_check_reduced_costs(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving doubleton_action::postsolve." << std::endl ; # endif # endif }
/* 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) ; }
/* We're here to undo the bound changes that were put in place for forcing constraints. This is a bit trickier than it appears. Assume we are working with constraint r. The situation on arrival is that constraint r exists and is fully populated with fixed variables, all of which are nonbasic. Even though the constraint is tight, the logical s(r) is basic and the dual y(r) is zero. We may need to change that if a bound is relaxed to infinity on some variable x(t), making x(t)'s current nonbasic status untenable. We'll need to make s(r) nonbasic so that y(r) can be nonzero. Then we can make x(t) basic and use y(r) to force cbar(t) to zero. The code below will choose the variable x(t) whose reduced cost cbar(t) is most wrong and adjust y(r) to drive cbar(t) to zero using cbar(t) = c(t) - SUM{i\r} y(i) a(it) - y(r)a(rt) cbar(t) = cbar(t\r) - y(r)a(rt) Setting cbar(t) to zero, y(r) = cbar(t\r)/a(rt) We will need to scan row r, correcting cbar(j) for all x(j) entangled with the row. We may need to change the nonbasic status of x(j) if the adjustment causes cbar(j) to change sign. */ void forcing_constraint_action::postsolve(CoinPostsolveMatrix *prob) const { const action *const actions = actions_ ; const int nactions = nactions_ ; const double *colels = prob->colels_ ; const int *hrow = prob->hrow_ ; const CoinBigIndex *mcstrt = prob->mcstrt_ ; const int *hincol = prob->hincol_ ; const int *link = prob->link_ ; double *clo = prob->clo_ ; double *cup = prob->cup_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *rcosts = prob->rcosts_ ; double *acts = prob->acts_ ; double *rowduals = prob->rowduals_ ; const double ztoldj = prob->ztoldj_ ; const double ztolzb = prob->ztolzb_ ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 const double *sol = prob->sol_ ; # if PRESOLVE_DEBUG > 0 std::cout << "Entering forcing_constraint_action::postsolve, " << nactions << " constraints to process." << std::endl ; # endif presolve_check_threads(prob) ; presolve_check_free_list(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # endif /* Open a loop to process the actions. One action per constraint. */ for (const action *f = &actions[nactions-1] ; actions <= f ; f--) { const int irow = f->row ; const int nlo = f->nlo ; const int nup = f->nup ; const int ninrow = nlo+nup ; const int *rowcols = f->rowcols ; const double *bounds = f->bounds ; # if PRESOLVE_DEBUG > 1 std::cout << " Restoring constraint " << irow << ", " << ninrow << " variables." << std::endl ; # endif PRESOLVEASSERT(prob->getRowStatus(irow) == CoinPrePostsolveMatrix::basic) ; PRESOLVEASSERT(rowduals[irow] == 0.0) ; /* Process variables where the upper bound is relaxed. * If the variable is basic, we should leave the status unchanged. Relaxing the bound cannot make nonbasic status feasible. * The bound change may be a noop, in which nothing needs to be done. * Otherwise, the status should be set to NBLB. */ bool dualfeas = true ; for (int k = 0 ; k < nlo ; k++) { const int jcol = rowcols[k] ; PRESOLVEASSERT(fabs(sol[jcol]-clo[jcol]) <= ztolzb) ; const double cbarj = rcosts[jcol] ; const double olduj = cup[jcol] ; const double newuj = bounds[k] ; const bool change = (fabs(newuj-olduj) > ztolzb) ; # if PRESOLVE_DEBUG > 2 std::cout << " x(" << jcol << ") " << prob->columnStatusString(jcol) << " cbar = " << cbarj << ", lb = " << clo[jcol] << ", ub = " << olduj << " -> " << newuj ; # endif if (change && prob->getColumnStatus(jcol) != CoinPrePostsolveMatrix::basic) { prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ; if (cbarj < -ztoldj || clo[jcol] <= -COIN_DBL_MAX) dualfeas = false ; } cup[jcol] = bounds[k] ; # if PRESOLVE_DEBUG > 2 std::cout << " -> " << prob->columnStatusString(jcol) << "." << std::endl ; # endif } /* Process variables where the lower bound is relaxed. The comments above apply. */ for (int k = nlo ; k < ninrow ; k++) { const int jcol = rowcols[k] ; PRESOLVEASSERT(fabs(sol[jcol]-cup[jcol]) <= ztolzb) ; const double cbarj = rcosts[jcol] ; const double oldlj = clo[jcol] ; const double newlj = bounds[k] ; const bool change = (fabs(newlj-oldlj) > ztolzb) ; # if PRESOLVE_DEBUG > 2 std::cout << " x(" << jcol << ") " << prob->columnStatusString(jcol) << " cbar = " << cbarj << ", ub = " << cup[jcol] << ", lb = " << oldlj << " -> " << newlj ; # endif if (change && prob->getColumnStatus(jcol) != CoinPrePostsolveMatrix::basic) { prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ; if (cbarj > ztoldj || cup[jcol] >= COIN_DBL_MAX) dualfeas = false ; } clo[jcol] = bounds[k] ; # if PRESOLVE_DEBUG > 2 std::cout << " -> " << prob->columnStatusString(jcol) << "." << std::endl ; # endif } /* The reduced costs and status for the columns may or may not be ok for the relaxed column bounds. If not, find the variable x<joow> most out-of-whack with respect to reduced cost and calculate the value of y<irow> required to reduce cbar<joow> to zero. */ if (dualfeas == false) { int joow = -1 ; double yi = 0.0 ; for (int k = 0 ; k < ninrow ; k++) { int jcol = rowcols[k] ; CoinBigIndex kk = presolve_find_row2(irow,mcstrt[jcol], hincol[jcol],hrow,link) ; const double &cbarj = rcosts[jcol] ; const CoinPrePostsolveMatrix::Status statj = prob->getColumnStatus(jcol) ; if ((cbarj < -ztoldj && statj != CoinPrePostsolveMatrix::atUpperBound) || (cbarj > ztoldj && statj != CoinPrePostsolveMatrix::atLowerBound)) { double yi_j = cbarj/colels[kk] ; if (fabs(yi_j) > fabs(yi)) { joow = jcol ; yi = yi_j ; } # if PRESOLVE_DEBUG > 3 std::cout << " oow: x(" << jcol << ") " << prob->columnStatusString(jcol) << " cbar " << cbarj << " aij " << colels[kk] << " corr " << yi_j << "." << std::endl ; # endif } } assert(joow != -1) ; /* Make x<joow> basic and set the row status according to whether we're tight at the lower or upper bound. Keep in mind the convention that a <= constraint has a slack 0 <= s <= infty, while a >= constraint has a surplus -infty <= s <= 0. */ # if PRESOLVE_DEBUG > 1 std::cout << " Adjusting row dual; x(" << joow << ") " << prob->columnStatusString(joow) << " -> " << statusName(CoinPrePostsolveMatrix::basic) << ", y = 0.0 -> " << yi << "." << std::endl ; # endif prob->setColumnStatus(joow,CoinPrePostsolveMatrix::basic) ; if (acts[irow]-rlo[irow] < rup[irow]-acts[irow]) prob->setRowStatus(irow,CoinPrePostsolveMatrix::atUpperBound) ; else prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound) ; rowduals[irow] = yi ; # if PRESOLVE_DEBUG > 1 std::cout << " Row status " << prob->rowStatusString(irow) << ", lb = " << rlo[irow] << ", ax = " << acts[irow] << ", ub = " << rup[irow] << "." << std::endl ; # endif /* Now correct the reduced costs for other variables in the row. This may cause a reduced cost to change sign, in which case we need to change status. The code implicitly assumes that if it's necessary to change the status of a variable because the reduced cost has changed sign, then it will be possible to do it. I'm not sure I could prove that, however. -- lh, 121108 -- */ for (int k = 0 ; k < ninrow ; k++) { int jcol = rowcols[k] ; CoinBigIndex kk = presolve_find_row2(irow,mcstrt[jcol], hincol[jcol],hrow,link) ; const double old_cbarj = rcosts[jcol] ; rcosts[jcol] -= yi*colels[kk] ; const double new_cbarj = rcosts[jcol] ; if ((old_cbarj < 0) != (new_cbarj < 0)) { if (new_cbarj < -ztoldj && cup[jcol] < COIN_DBL_MAX) prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ; else if (new_cbarj > ztoldj && clo[jcol] > -COIN_DBL_MAX) prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ; } # if PRESOLVE_DEBUG > 3 const CoinPrePostsolveMatrix::Status statj = prob->getColumnStatus(jcol) ; std::cout << " corr: x(" << jcol << ") " << prob->columnStatusString(jcol) << " cbar " << new_cbarj ; if ((new_cbarj < -ztoldj && statj != CoinPrePostsolveMatrix::atUpperBound) || (new_cbarj > ztoldj && statj != CoinPrePostsolveMatrix::atLowerBound) || (statj == CoinPrePostsolveMatrix::basic && fabs(new_cbarj) > ztoldj)) std::cout << " error!" << std::endl ; else std::cout << "." << std::endl ; # endif } } # if PRESOLVE_DEBUG > 0 presolve_check_nbasic(prob) ; # endif } # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_threads(prob) ; presolve_check_sol(prob,2,2,2) ; presolve_check_nbasic(prob) ; # if PRESOLVE_DEBUG > 0 std::cout << "Leaving forcing_constraint_action::postsolve." << std::endl ; # endif # endif }
/* 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) ; }
const CoinPresolveAction *drop_empty_rows_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { int ncols = prob->ncols_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int *hrow = prob->hrow_; int nrows = prob->nrows_; // This is done after row copy needed //int *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; //int *hcol = prob->hcol_; double *rlo = prob->rlo_; double *rup = prob->rup_; unsigned char *rowstat = prob->rowstat_; double *acts = prob->acts_; int * originalRow = prob->originalRow_; //presolvehlink *rlink = prob->rlink_; bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; // Relax tolerance double tolerance = 10.0*prob->feasibilityTolerance_; int i; int nactions = 0; for (i=0; i<nrows; i++) if (hinrow[i] == 0) nactions++; if (nactions == 0) return next; else { action *actions = new action[nactions]; int * rowmapping = new int [nrows]; nactions = 0; int nrows2=0; for (i=0; i<nrows; i++) { if (hinrow[i] == 0) { action &e = actions[nactions]; # if PRESOLVE_DEBUG if (nactions == 0) printf("UNUSED ROWS: "); else if (i < 100 && nactions%25 == 0) printf("\n") ; else if (i >= 100 && i < 1000 && nactions%19 == 0) printf("\n") ; else if (i >= 1000 && nactions%15 == 0) printf("\n") ; printf("%d ", i); # endif nactions++; if (rlo[i] > 0.0 || rup[i] < 0.0) { if ((rlo[i]<=tolerance && rup[i]>=-tolerance)||fixInfeasibility) { rlo[i]=0.0; rup[i]=0.0; } else { prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) <<i <<rlo[i] <<rup[i] <<CoinMessageEol; break; } } e.row = i; e.rlo = rlo[i]; e.rup = rup[i]; rowmapping[i]=-1; } else { // move down - we want to preserve order rlo[nrows2]=rlo[i]; rup[nrows2]=rup[i]; originalRow[nrows2]=i; if (acts) { acts[nrows2]=acts[i]; rowstat[nrows2]=rowstat[i]; } rowmapping[i]=nrows2++; } } // remap matrix for (i=0;i<ncols;i++) { int j; for (j=mcstrt[i];j<mcstrt[i]+hincol[i];j++) hrow[j] = rowmapping[hrow[j]]; } delete [] rowmapping; prob->nrows_ = nrows2; #if PRESOLVE_DEBUG presolve_check_nbasic(prob) ; if (nactions) printf("\ndropped %d rows\n", nactions); #endif return (new drop_empty_rows_action(nactions, actions, next)); } }