// Copyright (C) 2002, International Business Machines // Corporation and others. All Rights Reserved. #include #include #include "CoinHelperFunctions.hpp" #include "CoinPresolveMatrix.hpp" #include "CoinPresolveEmpty.hpp" #include "CoinMessage.hpp" /* \file Routines to remove/reinsert empty columns and rows. */ /* Physically remove empty columns, compressing mcstrt and hincol. The major side effect is that columns are renumbered, thus clink_ is no longer valid and must be rebuilt. It's necessary to rebuild clink_ in order to do direct conversion of a CoinPresolveMatrix to a CoinPostsolveMatrix by transferring the data arrays. Without clink_, it's impractical to build link_ to match the transferred bulk storage. */ const CoinPresolveAction *drop_empty_cols_action::presolve (CoinPresolveMatrix *prob, int *ecols, int necols, const CoinPresolveAction *next) { int ncols = prob->ncols_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; presolvehlink *clink = prob->clink_; double *clo = prob->clo_; double *cup = prob->cup_; double *dcost = prob->cost_; const double ztoldj = prob->ztoldj_; unsigned char * integerType = prob->integerType_; int * originalColumn = prob->originalColumn_; const double maxmin = prob->maxmin_; double * sol = prob->sol_; unsigned char * colstat = prob->colstat_; action *actions = new action[necols]; int * colmapping = new int [ncols+1]; bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; CoinZeroN(colmapping,ncols); int i; for (i=necols-1; i>=0; i--) { int jcol = ecols[i]; colmapping[jcol]=-1; action &e = actions[i]; e.jcol = jcol; e.clo = clo[jcol]; e.cup = cup[jcol]; // adjust if integer if (integerType[jcol]) { e.clo = ceil(e.clo-1.0e-9); e.cup = floor(e.cup+1.0e-9); if (e.clo>e.cup&&!fixInfeasibility) { // infeasible prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, prob->messages()) < 0.0) { if (-PRESOLVE_INF < e.clo) e.sol = e.clo; else { prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDB, prob->messages()) <status_ |= 2; break; } } else { if (e.cup < PRESOLVE_INF) e.sol = e.cup; else { prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDA, prob->messages()) <status_ |= 2; break; } } #if PRESOLVE_DEBUG if (e.sol * dcost[jcol]) { //printf("\a>>>NON-ZERO COST FOR EMPTY COL %d: %g\n", jcol, dcost[jcol]); } #endif prob->change_bias(e.sol * dcost[jcol]); } int ncols2=0; // now move remaining ones down for (i=0;i= 0 ; oldj = clink[oldj].pre) { presolvehlink &oldlnk = clink[oldj] ; int newj = colmapping[oldj] ; assert(newj >= 0 && newj <= ncols2) ; presolvehlink &newlnk = newclink[newj] ; if (oldlnk.suc >= 0) { newlnk.suc = colmapping[oldlnk.suc] ; } else { newlnk.suc = NO_LINK ; } if (oldlnk.pre >= 0) { newlnk.pre = colmapping[oldlnk.pre] ; } else { newlnk.pre = NO_LINK ; } } delete [] clink ; prob->clink_ = newclink ; } delete [] colmapping; prob->ncols_ = ncols2; return (new drop_empty_cols_action(necols, actions, next)); } const CoinPresolveAction *drop_empty_cols_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { const int *hincol = prob->hincol_; // const double *clo = prob->clo_; // const double *cup = prob->cup_; int ncols = prob->ncols_; int i; int nempty = 0; int * empty = new int [ncols]; CoinBigIndex nelems2 = 0 ; // count empty cols for (i=0; i= 100 && i < 1000 && nempty%19 == 0) printf("\n") ; else if (i >= 1000 && nempty%15 == 0) printf("\n") ; printf("%d ", i); #endif empty[nempty++] = i; } } prob->nelems_ = nelems2 ; if (nempty) { #if PRESOLVE_DEBUG printf("\ndropped %d cols\n", nempty); #endif next = drop_empty_cols_action::presolve(prob, empty, nempty, next); } delete [] empty; return (next); } 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; } const CoinPresolveAction *drop_empty_rows_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { int ncols = prob->ncols_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int *hrow = prob->hrow_; int nrows = prob->nrows_; // This is done after row copy needed //int *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; //int *hcol = prob->hcol_; double *rlo = prob->rlo_; double *rup = prob->rup_; unsigned char *rowstat = prob->rowstat_; double *acts = prob->acts_; int * originalRow = prob->originalRow_; //presolvehlink *rlink = prob->rlink_; bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; int i; int nactions = 0; for (i=0; i= 100 && i < 1000 && nactions%19 == 0) printf("\n") ; else if (i >= 1000 && nactions%15 == 0) printf("\n") ; printf("%d ", i); # endif nactions++; if (rlo[i] > 0.0 || rup[i] < 0.0) { if ((rlo[i]<=prob->feasibilityTolerance_ && rup[i]>=-prob->feasibilityTolerance_)||fixInfeasibility) { rlo[i]=0.0; rup[i]=0.0; } else { prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) <nrows_ = nrows2; #if PRESOLVE_DEBUG if (nactions) printf("\ndropped %d rows\n", nactions); #endif return (new drop_empty_rows_action(nactions, actions, next)); } } 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_irow; 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;irow; // 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; }