/* 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 ; }
/* 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 ; }
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 ; }
/* * 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 }
/* 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 tripleton_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 *rcosts = prob->rcosts_; double *acts = prob->acts_; double *rowduals = prob->rowduals_; unsigned char *colstat = prob->colstat_; unsigned char *rowstat = prob->rowstat_; const double maxmin = prob->maxmin_; # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY char *cdone = prob->cdone_; char *rdone = prob->rdone_; # endif CoinBigIndex &free_list = prob->free_list_; const double ztolzb = prob->ztolzb_; const double ztoldj = prob->ztoldj_; // Space for accumulating two columns int nrows = prob->nrows_; int * index1 = new int[nrows]; double * element1 = new double[nrows]; memset(element1,0,nrows*sizeof(double)); int * index2 = new int[nrows]; double * element2 = new double[nrows]; memset(element2,0,nrows*sizeof(double)); for (const action *f = &actions[nactions-1]; actions<=f; f--) { int irow = f->row; // probably don't need this double ylo0 = f->cloy; double yup0 = f->cupy; double coeffx = f->coeffx; double coeffy = f->coeffy; double coeffz = f->coeffz; int jcolx = f->icolx; int jcoly = f->icoly; int jcolz = f->icolz; // needed? double rhs = f->rlo; /* the column was in the reduced problem */ PRESOLVEASSERT(cdone[jcolx] && rdone[irow]==DROP_ROW&&cdone[jcolz]); PRESOLVEASSERT(cdone[jcoly]==DROP_COL); // probably don't need this rlo[irow] = f->rlo; rup[irow] = f->rup; // probably don't need this clo[jcoly] = ylo0; cup[jcoly] = yup0; dcost[jcoly] = f->costy; dcost[jcolx] += f->costy*coeffx/coeffy; dcost[jcolz] += f->costy*coeffz/coeffy; // this is why we want coeffx < coeffy (55) sol[jcoly] = (rhs - coeffx * sol[jcolx] - coeffz * sol[jcolz]) / coeffy; // since this row is fixed acts[irow] = rhs; // acts[irow] always ok, since slack is fixed if (rowstat) prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound); // CLAIM: // if the new pi value is chosen to keep the reduced cost // of col x at its prior value, then the reduced cost of // col y will be 0. // also have to update row activities and bounds for rows affected by jcoly // // sol[jcolx] was found for coeffx that // was += colels[kcoly] * coeff_factor; // where coeff_factor == -coeffx / coeffy // // its contribution to activity was // (colels[kcolx] + colels[kcoly] * coeff_factor) * sol[jcolx] (1) // // After adjustment, the two columns contribute: // colels[kcoly] * sol[jcoly] + colels[kcolx] * sol[jcolx] // == colels[kcoly] * ((rhs - coeffx * sol[jcolx]) / coeffy) + colels[kcolx] * sol[jcolx] // == colels[kcoly] * rhs/coeffy + colels[kcoly] * coeff_factor * sol[jcolx] + colels[kcolx] * sol[jcolx] // colels[kcoly] * rhs/coeffy + the expression (1) // // therefore, we must increase the row bounds by colels[kcoly] * rhs/coeffy, // which is similar to the bias double djy = maxmin * dcost[jcoly]; double djx = maxmin * dcost[jcolx]; double djz = maxmin * dcost[jcolz]; double bounds_factor = rhs/coeffy; // need to reconstruct x and z double multiplier1 = coeffx/coeffy; double multiplier2 = coeffz/coeffy; int * indy = reinterpret_cast<int *>(f->colel+f->ncoly); int ystart = NO_LINK; int nX=0,nZ=0; int i,iRow; for (i=0; i<f->ncoly; ++i) { int iRow = indy[i]; double yValue = f->colel[i]; CoinBigIndex k = free_list; assert(k >= 0 && k < prob->bulk0_) ; free_list = link[free_list]; if (iRow != irow) { // are these tests always true??? // undo elim_tripleton(1) if (-PRESOLVE_INF < rlo[iRow]) rlo[iRow] += yValue * bounds_factor; // undo elim_tripleton(2) if (rup[iRow] < PRESOLVE_INF) rup[iRow] += yValue * bounds_factor; acts[iRow] += yValue * bounds_factor; djy -= rowduals[iRow] * yValue; } hrow[k] = iRow; PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow); colels[k] = yValue; link[k] = ystart; ystart = k; element1[iRow]=yValue*multiplier1; index1[nX++]=iRow; element2[iRow]=yValue*multiplier2; index2[nZ++]=iRow; } # if PRESOLVE_CONSISTENCY presolve_check_free_list(prob) ; # endif mcstrt[jcoly] = ystart; hincol[jcoly] = f->ncoly; // find the tail CoinBigIndex k=mcstrt[jcolx]; CoinBigIndex last = NO_LINK; int numberInColumn = hincol[jcolx]; int numberToDo=numberInColumn; for (i=0; i<numberToDo; ++i) { iRow = hrow[k]; assert (iRow>=0&&iRow<nrows); double value = colels[k]+element1[iRow]; element1[iRow]=0.0; if (fabs(value)>=1.0e-15) { colels[k]=value; last=k; k = link[k]; if (iRow != irow) djx -= rowduals[iRow] * value; } else { numberInColumn--; // add to free list int nextk = link[k]; link[k]=free_list; free_list=k; assert (k>=0); k=nextk; if (last!=NO_LINK) link[last]=k; else mcstrt[jcolx]=k; } } for (i=0;i<nX;i++) { int iRow = index1[i]; double xValue = element1[iRow]; element1[iRow]=0.0; if (fabs(xValue)>=1.0e-15) { if (iRow != irow) djx -= rowduals[iRow] * xValue; numberInColumn++; CoinBigIndex k = free_list; assert(k >= 0 && k < prob->bulk0_) ; free_list = link[free_list]; hrow[k] = iRow; PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow); colels[k] = xValue; if (last!=NO_LINK) link[last]=k; else mcstrt[jcolx]=k; last = k; } } # if PRESOLVE_CONSISTENCY presolve_check_free_list(prob) ; # endif link[last]=NO_LINK; assert(numberInColumn); hincol[jcolx] = numberInColumn; // find the tail k=mcstrt[jcolz]; last = NO_LINK; numberInColumn = hincol[jcolz]; numberToDo=numberInColumn; for (i=0; i<numberToDo; ++i) { iRow = hrow[k]; assert (iRow>=0&&iRow<nrows); double value = colels[k]+element2[iRow]; element2[iRow]=0.0; if (fabs(value)>=1.0e-15) { colels[k]=value; last=k; k = link[k]; if (iRow != irow) djz -= rowduals[iRow] * value; } else { numberInColumn--; // add to free list int nextk = link[k]; assert(free_list>=0); link[k]=free_list; free_list=k; assert (k>=0); k=nextk; if (last!=NO_LINK) link[last]=k; else mcstrt[jcolz]=k; } } for (i=0;i<nZ;i++) { int iRow = index2[i]; double zValue = element2[iRow]; element2[iRow]=0.0; if (fabs(zValue)>=1.0e-15) { if (iRow != irow) djz -= rowduals[iRow] * zValue; numberInColumn++; CoinBigIndex k = free_list; assert(k >= 0 && k < prob->bulk0_) ; free_list = link[free_list]; hrow[k] = iRow; PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow); colels[k] = zValue; if (last!=NO_LINK) link[last]=k; else mcstrt[jcolz]=k; last = k; } } # if PRESOLVE_CONSISTENCY presolve_check_free_list(prob) ; # endif link[last]=NO_LINK; assert(numberInColumn); hincol[jcolz] = numberInColumn; // The only problem with keeping the reduced costs the way they were // was that the variable's bound may have moved, requiring it // to become basic. //printf("djs x - %g (%g), y - %g (%g)\n",djx,coeffx,djy,coeffy); if (colstat) { if (prob->columnIsBasic(jcolx) || (fabs(clo[jcolx] - sol[jcolx]) < ztolzb && rcosts[jcolx] >= -ztoldj) || (fabs(cup[jcolx] - sol[jcolx]) < ztolzb && rcosts[jcolx] <= ztoldj) || (prob->getColumnStatus(jcolx) ==CoinPrePostsolveMatrix::isFree&& fabs(rcosts[jcolx]) <= ztoldj)) { // colx or y is fine as it is - make coly basic prob->setColumnStatus(jcoly,CoinPrePostsolveMatrix::basic); // 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[jcolx] = djx - rowduals[irow] * coeffx; # if PRESOLVE_DEBUG if (prob->columnIsBasic(jcolx)&&fabs(rcosts[jcolx])>1.0e-5) printf("bad dj %d %g\n",jcolx,rcosts[jcolx]); # endif rcosts[jcolz] = djz - rowduals[irow] * coeffz; //if (prob->columnIsBasic(jcolz)) //assert (fabs(rcosts[jcolz])<1.0e-5); rcosts[jcoly] = 0.0; } else { prob->setColumnStatus(jcolx,CoinPrePostsolveMatrix::basic); prob->setColumnStatusUsingValue(jcoly); // change rowduals[jcolx] enough to cancel out rcosts[jcolx] rowduals[irow] = djx / coeffx; rcosts[jcolx] = 0.0; // change rowduals[jcolx] enough to cancel out rcosts[jcolx] //rowduals[irow] = djz / coeffz; //rcosts[jcolz] = 0.0; rcosts[jcolz] = djz - rowduals[irow] * coeffz; rcosts[jcoly] = djy - rowduals[irow] * coeffy; } } 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; } // DEBUG CHECK # if PRESOLVE_DEBUG { CoinBigIndex k = mcstrt[jcolx]; int nx = hincol[jcolx]; double dj = maxmin * dcost[jcolx]; for (int i=0; i<nx; ++i) { int row = hrow[k]; 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]; int ny = hincol[jcoly]; double dj = maxmin * dcost[jcoly]; for (int i=0; i<ny; ++i) { int row = hrow[k]; double coeff = colels[k]; k = link[k]; dj -= rowduals[row] * coeff; //printf("b %d coeff %g dual %g dj %g\n", // row,coeff,rowduals[row],dj); } 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; //exit(0); } # endif # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY cdone[jcoly] = TRIPLETON; rdone[irow] = TRIPLETON; # endif } delete [] index1; delete [] element1; delete [] index2; delete [] element2; # if PRESOLVE_CONSISTENCY presolve_check_threads(prob) ; # endif }
void CoinPostsolveMatrix::assignPresolveToPostsolve (CoinPresolveMatrix *&preObj) { /* Start with simple data --- allocated and current size. */ ncols0_ = preObj->ncols0_ ; nrows0_ = preObj->nrows0_ ; nelems0_ = preObj->nelems0_ ; bulk0_ = preObj->bulk0_ ; ncols_ = preObj->ncols_ ; nrows_ = preObj->nrows_ ; nelems_ = preObj->nelems_ ; /* Now bring over the column-major matrix and other problem data. */ mcstrt_ = preObj->mcstrt_ ; preObj->mcstrt_ = 0 ; hincol_ = preObj->hincol_ ; preObj->hincol_ = 0 ; hrow_ = preObj->hrow_ ; preObj->hrow_ = 0 ; colels_ = preObj->colels_ ; preObj->colels_ = 0 ; cost_ = preObj->cost_ ; preObj->cost_ = 0 ; originalOffset_ = preObj->originalOffset_ ; clo_ = preObj->clo_ ; preObj->clo_ = 0 ; cup_ = preObj->cup_ ; preObj->cup_ = 0 ; rlo_ = preObj->rlo_ ; preObj->rlo_ = 0 ; rup_ = preObj->rup_ ; preObj->rup_ = 0 ; originalColumn_ = preObj->originalColumn_ ; preObj->originalColumn_ = 0 ; originalRow_ = preObj->originalRow_ ; preObj->originalRow_ = 0 ; ztolzb_ = preObj->ztolzb_ ; ztoldj_ = preObj->ztoldj_ ; maxmin_ = preObj->maxmin_ ; /* Now the problem solution. Often this will be empty, but that's not a problem. */ sol_ = preObj->sol_ ; preObj->sol_ = 0 ; rowduals_ = preObj->rowduals_ ; preObj->rowduals_ = 0 ; acts_ = preObj->acts_ ; preObj->acts_ = 0 ; rcosts_ = preObj->rcosts_ ; preObj->rcosts_ = 0 ; colstat_ = preObj->colstat_ ; preObj->colstat_ = 0 ; rowstat_ = preObj->rowstat_ ; preObj->rowstat_ = 0 ; /* The CoinPostsolveMatrix comes with messages and a handler, but replace them with the versions from the CoinPresolveObject, in case they've been customized. Let preObj believe it's no longer responsible for the handler. */ if (defaultHandler_ == true) delete handler_ ; handler_ = preObj->handler_ ; preObj->defaultHandler_ = false ; messages_ = preObj->messages_ ; /* Initialise the postsolve portions of this object. Which amounts to setting up the thread links to match the column-major matrix representation. This would be trivial except that the presolve matrix is loosely packed. We can either compress the matrix, or record the existing free space pattern. Bet that the latter is more efficient. Remember that mcstrt_[ncols_] actually points to the end of the bulk storage area, so when we process the last column in the bulk storage area, we'll add the free space block at the end of bulk storage to the free list. We need to allow for a 0x0 matrix here --- a pathological case, but it slips in when (for example) confirming a solution in an ILP code. */ free_list_ = NO_LINK ; maxlink_ = bulk0_ ; link_ = new CoinBigIndex [maxlink_] ; if (ncols_ > 0) { CoinBigIndex minkcs = -1 ; for (int j = 0 ; j < ncols_ ; j++) { CoinBigIndex kcs = mcstrt_[j] ; int lenj = hincol_[j] ; assert(lenj > 0) ; CoinBigIndex kce = kcs+lenj-1 ; CoinBigIndex k ; for (k = kcs ; k < kce ; k++) { link_[k] = k+1 ; } link_[k++] = NO_LINK ; if (preObj->clink_[j].pre == NO_LINK) { minkcs = kcs ; } int nxtj = preObj->clink_[j].suc ; assert(nxtj >= 0 && nxtj <= ncols_) ; CoinBigIndex nxtcs = mcstrt_[nxtj] ; for ( ; k < nxtcs ; k++) { link_[k] = free_list_ ; free_list_ = k ; } } assert(minkcs >= 0) ; if (minkcs > 0) { for (CoinBigIndex k = 0 ; k < minkcs ; k++) { link_[k] = free_list_ ; free_list_ = k ; } } } else { for (CoinBigIndex k = 0 ; k < maxlink_ ; k++) { link_[k] = free_list_ ; free_list_ = k ; } } /* That's it, preObj can die now. */ delete preObj ; preObj = 0 ; # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY /* These are used to track the action of postsolve transforms during debugging. */ cdone_ = new char [ncols0_] ; CoinFillN(cdone_,ncols_,PRESENT_IN_REDUCED) ; CoinZeroN(cdone_+ncols_,ncols0_-ncols_) ; rdone_ = new char [nrows0_] ; CoinFillN(rdone_,nrows_,PRESENT_IN_REDUCED) ; CoinZeroN(rdone_+nrows_,nrows0_-nrows_) ; # else cdone_ = 0 ; rdone_ = 0 ; # endif # if PRESOLVE_CONSISTENCY presolve_check_free_list(this,true) ; presolve_check_threads(this) ; # endif return ; }
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 ; }
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 }
void drop_empty_rows_action::postsolve(CoinPostsolveMatrix *prob) const { const int nactions = nactions_; const action *const actions = actions_; int ncols = prob->ncols_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int *hrow = prob->hrow_; double *rlo = prob->rlo_; double *rup = prob->rup_; unsigned char *rowstat = prob->rowstat_; double *rowduals = prob->rowduals_; double *acts = prob->acts_; # if PRESOLVE_DEBUG char *rdone = prob->rdone_; # endif int nrows0 = prob->nrows0_; int nrows = prob->nrows_; int * rowmapping = new int [nrows0]; CoinZeroN(rowmapping,nrows0) ; int i, action_i; for (action_i = 0; action_i<nactions; action_i++) { const action *e = &actions[action_i]; int hole = e->row; rowmapping[hole]=-1; } // move data for (i=nrows0-1; i>=0; i--) { if (!rowmapping[i]) { // not a hole nrows--; rlo[i]=rlo[nrows]; rup[i]=rup[nrows]; acts[i]=acts[nrows]; rowduals[i]=rowduals[nrows]; if (rowstat) rowstat[i] = rowstat[nrows]; # if PRESOLVE_DEBUG rdone[i] = rdone[nrows] ; # endif } } assert (!nrows); // set up mapping for matrix for (i=0;i<nrows0;i++) { if (!rowmapping[i]) rowmapping[nrows++]=i; } for (int j=0; j<ncols; j++) { CoinBigIndex start = mcstrt[j]; CoinBigIndex end = start + hincol[j]; for (CoinBigIndex k=start; k<end; ++k) { hrow[k] = rowmapping[hrow[k]]; } } delete [] rowmapping; for (action_i = 0; action_i < nactions; action_i++) { const action *e = &actions[action_i]; int irow = e->row; // Now recreate irow rlo[irow] = e->rlo; rup[irow] = e->rup; if (rowstat) prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic); rowduals[irow] = 0.0; // ??? acts[irow] = 0.0; # if PRESOLVE_DEBUG rdone[irow] = DROP_ROW; # endif } prob->nrows_ = prob->nrows_+nactions; # if PRESOLVE_DEBUG presolve_check_threads(prob) ; # endif }
void drop_empty_cols_action::postsolve(CoinPostsolveMatrix *prob) const { const int nactions = nactions_; const action *const actions = actions_; int ncols = prob->ncols_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; // int *hrow = prob->hrow_; double *clo = prob->clo_; double *cup = prob->cup_; double *sol = prob->sol_; double *cost = prob->cost_; double *rcosts = prob->rcosts_; unsigned char *colstat = prob->colstat_; const double maxmin = prob->maxmin_; int ncols2 = ncols+nactions; int * colmapping = new int [ncols2]; CoinZeroN(colmapping,ncols2); # if PRESOLVE_DEBUG char *cdone = prob->cdone_; # endif int action_i; for (action_i = 0; action_i < nactions; action_i++) { const action *e = &actions[action_i]; int jcol = e->jcol; colmapping[jcol]=-1; } int i; // now move remaining ones up for (i=ncols2-1;i>=0;i--) { if (!colmapping[i]) { ncols--; mcstrt[i] = mcstrt[ncols]; hincol[i] = hincol[ncols]; clo[i] = clo[ncols]; cup[i] = cup[ncols]; cost[i] = cost[ncols]; if (sol) sol[i] = sol[ncols]; if (rcosts) rcosts[i] = rcosts[ncols]; if (colstat) colstat[i] = colstat[ncols]; # if PRESOLVE_DEBUG cdone[i] = cdone[ncols]; # endif } } assert (!ncols); delete [] colmapping; for (action_i = 0; action_i < nactions; action_i++) { const action *e = &actions[action_i]; int jcol = e->jcol; // now recreate jcol clo[jcol] = e->clo; cup[jcol] = e->cup; if (sol) sol[jcol] = e->sol; cost[jcol] = e->cost; if (rcosts) rcosts[jcol] = maxmin*cost[jcol]; hincol[jcol] = 0; mcstrt[jcol] = NO_LINK ; # if PRESOLVE_DEBUG cdone[jcol] = DROP_COL; # endif if (colstat) prob->setColumnStatusUsingValue(jcol); } prob->ncols_ += nactions; # if PRESOLVE_CONSISTENCY presolve_check_threads(prob) ; # endif }