// Copyright (C) 2002, International Business Machines // Corporation and others. All Rights Reserved. #include #include #include "CoinPresolveMatrix.hpp" #include "CoinPresolveFixed.hpp" #include "CoinPresolveTighten.hpp" #include "CoinPresolveUseless.hpp" #include "CoinHelperFunctions.hpp" const char *do_tighten_action::name() const { return ("do_tighten_action"); } // This is ekkredc2. // This fairly simple transformation is not mentioned in the paper. // Say there is a costless variable such all its constraints // would be satisfied as it approaches plus or minus infinity, // because all its constraints have only one bound, and increasing/decreasing // the variable makes the row activity grow away from the bound // (in the right direction). // // If the variable is unbounded in that direction, // that means we can determine right now how large it needs // to get in order to satisfy the constraints, so we can // just drop the variable and those constraints from the problem. // // If the variable *is* bounded in that direction, // there is no reason not to set it to that bound. // This effectively weakens the constraints, and in fact // may be subsequently presolved away. // // Note that none of the constraints may be bounded both above and below, // since then we don't know which way to move the variable in order // to satisfy the constraint. // // To drop constraints, we just make them useless and let other // transformations take care of the rest. // // Note that more than one such costless unbounded variable // may be part of a given constraint. // In that case, the first one processed will make the // constraint useless, and the second will ignore it. // In postsolve, the first will be responsible for satisfying // the constraint. // // Note that if the constraints are dropped (as in the first case), // then we just make them useless. It is subsequently discovered // the the variable does not appear in any constraints, and since it // has no cost it is just set to some value (either zero or a bound) // and removed (by remove_empty_cols). // // oddly, pilots and baxter do *worse* when this transform is applied. const CoinPresolveAction *do_tighten_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_; int nrows = prob->nrows_; 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 *fixup_cols = new int[ncols]; int nfixup_cols = 0; int *fixdown_cols = new int[ncols]; int nfixdown_cols = 0; int *useless_rows = new int[nrows]; 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_&16384)!=0; // singleton columns are especially likely to be caught here for (iLook=0;iLookcup[j]&&!fixInfeasibility) { // infeasible prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, prob->messages()) < 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 printf("TIGHTEN UP: %d\n", j); #endif fixup_cols[nfixup_cols] = j; ++nfixup_cols; } else if (iflag==-1&&clo[j]>-1.0e10) { // symmetric case //mpre[j] = PRESOLVE_XUP; #if PRESOLVE_DEBUG printf("TIGHTEN DOWN: %d\n", j); #endif fixdown_cols[nfixdown_cols] = j; ++nfixdown_cols; } 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; kcol = j; s->direction = iflag; s->rows = new int[hincol[j]]; s->lbound = new double[hincol[j]]; s->ubound = new double[hincol[j]]; #ifdef PRESOLVE_DEBUG printf("TIGHTEN FREE: %d ", j); #endif int nr = 0; prob->addCol(j); for (CoinBigIndex k=kcs; kaddRow(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; #ifdef PRESOLVE_DEBUG printf("%d ", irow); #endif } } s->nrows = nr; #ifdef PRESOLVE_DEBUG printf("\n"); #endif } } } } } #if PRESOLVE_SUMMARY if (nfixdown_cols || nfixup_cols || nuseless_rows) { printf("NTIGHTENED: %d %d %d\n", 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) { next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols, true, next); } delete[]fixdown_cols; if (nfixup_cols) { next = make_fixed_action::presolve(prob, fixup_cols, nfixup_cols, false, next); } delete[]fixup_cols; if (prob->tuning_) { double thisTime=CoinCpuTime(); int droppedRows = prob->countEmptyRows() - startEmptyRows ; int droppedColumns = prob->countEmptyCols() - startEmptyColumns; printf("CoinPresolveTighten(16) - %d rows, %d columns dropped in time %g, total %g\n", droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); } 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_; // int ncols = prob->ncols_; 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_; // const double ztolzb = prob->ztolzb_; 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;igetRowStatus(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 newrup) ); last_corrected = irow; // adjust to just meet newrlo (solve for correction) double new_correction = (newrlo - activity) / coeff; correction = new_correction; } else if (activity + correction * coeff > newrup) { last_corrected = irow; double new_correction = (newrup - activity) / coeff; 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 ZTOLDP && fabs(sol[jcol] - cup[jcol]) > ZTOLDP) { prob->setRowStatus(last_corrected,CoinPrePostsolveMatrix::atLowerBound); prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic); } } // leave until desctructor // deleteAction(rows,int *); // deleteAction(lbound,double *); // deleteAction(ubound,double *); } // leave until desctructor // deleteAction(actions_,action *); } do_tighten_action::~do_tighten_action() { if (nactions_ > 0) { for (int i = nactions_ - 1; i >= 0; --i) { delete[] actions_[i].rows; delete[] actions_[i].lbound; delete[] actions_[i].ubound; } deleteAction(actions_, action*); } }