/* 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 }
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_; // CoinBigIndex free_list = prob->free_list_; double *clo = prob->clo_; double *cup = prob->cup_; double *rlo = prob->rlo_; double *rup = prob->rup_; const double *sol = prob->sol_; double *rcosts = prob->rcosts_; double *acts = prob->acts_; double *rowduals = prob->rowduals_; const double ztoldj = prob->ztoldj_; const double ztolzb = prob->ztolzb_; 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; int k; /* Original comment: When we restore bounds here, we need to allow for the possibility that the restored bound is infinite. This implies a check for viable status. Hmmm ... I'm going to argue that in fact we have no choice: the status of the variable must reflect the value it was fixed at, else we lose feasibility. We don't care what the other bound does. -- lh, 040903 -- */ for (k=0; k<nlo; k++) { int jcol = rowcols[k]; cup[jcol] = bounds[k]; prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ; /* PRESOLVEASSERT(prob->getColumnStatus(jcol)!=CoinPrePostsolveMatrix::basic); if (cup[jcol] >= PRESOLVE_INF) { CoinPrePostsolveMatrix::Status statj = prob->getColumnStatus(jcol) ; if (statj == CoinPrePostsolveMatrix::atUpperBound) { if (clo[jcol] > -PRESOLVE_INF) { statj = CoinPrePostsolveMatrix::atLowerBound ; } else { statj = CoinPrePostsolveMatrix::isFree ; } prob->setColumnStatus(jcol,statj) ; } } */ } for (k=nlo; k<ninrow; k++) { int jcol = rowcols[k]; clo[jcol] = bounds[k]; prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ; /* PRESOLVEASSERT(prob->getColumnStatus(jcol)!=CoinPrePostsolveMatrix::basic); if (clo[jcol] <= -PRESOLVE_INF) { CoinPrePostsolveMatrix::Status statj = prob->getColumnStatus(jcol) ; if (statj == CoinPrePostsolveMatrix::atLowerBound) { if (cup[jcol] < PRESOLVE_INF) { statj = CoinPrePostsolveMatrix::atUpperBound ; } else { statj = CoinPrePostsolveMatrix::isFree ; } prob->setColumnStatus(jcol,statj) ; } } */ } PRESOLVEASSERT(prob->getRowStatus(irow)==CoinPrePostsolveMatrix::basic); PRESOLVEASSERT(rowduals[irow] == 0.0); // this is a lazy implementation. // we tightened the col bounds, then let them be eliminated // by repeated uses of FIX_VARIABLE and a final DROP_ROW. // Therefore, by this point the row has been marked basic, // the rowdual of this row is 0.0, // and the reduced costs for the cols may or may not be ok // for the relaxed column bounds. // // find the one most out of whack and fix it. int whacked = -1; double whack = 0.0; for (k=0; k<ninrow; k++) { int jcol = rowcols[k]; CoinBigIndex kk = presolve_find_row2(irow, mcstrt[jcol], hincol[jcol], hrow, link); // choose rowdual to cancel out reduced cost double whack0 = rcosts[jcol] / colels[kk]; if (((rcosts[jcol] > ztoldj && !(fabs(sol[jcol] - clo[jcol]) <= ztolzb)) || (rcosts[jcol] < -ztoldj && !(fabs(sol[jcol] - cup[jcol]) <= ztolzb))) && fabs(whack0) > fabs(whack)) { whacked = jcol; whack = whack0; } } if (whacked != -1) { prob->setColumnStatus(whacked,CoinPrePostsolveMatrix::basic); if (acts[irow]-rlo[irow]<rup[irow]-acts[irow]) prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound); else prob->setRowStatus(irow,CoinPrePostsolveMatrix::atUpperBound); rowduals[irow] = whack; for (k=0; k<ninrow; k++) { int jcol = rowcols[k]; CoinBigIndex kk = presolve_find_row2(irow, mcstrt[jcol], hincol[jcol], hrow, link); rcosts[jcol] -= (rowduals[irow] * colels[kk]); } } } # if PRESOLVE_CONSISTENCY presolve_check_threads(prob) ; # endif }