// Copyright (C) 2002, International Business Machines // Corporation and others. All Rights Reserved. //#define PRESOLVE_CONSISTENCY 1 //#define PRESOLVE_DEBUG 1 #include #include #include #include "CoinHelperFunctions.hpp" #include "CoinPackedMatrix.hpp" #include "ClpPackedMatrix.hpp" #include "ClpSimplex.hpp" #ifndef SLIM_CLP #include "ClpQuadraticObjective.hpp" #endif #include "ClpPresolve.hpp" #include "CoinPresolveMatrix.hpp" #include "CoinPresolveEmpty.hpp" #include "CoinPresolveFixed.hpp" #include "CoinPresolvePsdebug.hpp" #include "CoinPresolveSingleton.hpp" #include "CoinPresolveDoubleton.hpp" #include "CoinPresolveTripleton.hpp" #include "CoinPresolveZeros.hpp" #include "CoinPresolveSubst.hpp" #include "CoinPresolveForcing.hpp" #include "CoinPresolveDual.hpp" #include "CoinPresolveTighten.hpp" #include "CoinPresolveUseless.hpp" #include "CoinPresolveDupcol.hpp" #include "CoinPresolveImpliedFree.hpp" #include "CoinPresolveIsolated.hpp" #include "CoinMessage.hpp" ClpPresolve::ClpPresolve() : originalModel_(NULL), presolvedModel_(NULL), nonLinearValue_(0.0), originalColumn_(NULL), originalRow_(NULL), rowObjective_(NULL), paction_(0), ncols_(0), nrows_(0), nelems_(0), numberPasses_(5), substitution_(3), #ifndef CLP_NO_STD saveFile_(""), #endif presolveActions_(0) { } ClpPresolve::~ClpPresolve() { destroyPresolve(); } // Gets rid of presolve actions (e.g.when infeasible) void ClpPresolve::destroyPresolve() { const CoinPresolveAction *paction = paction_; while (paction) { const CoinPresolveAction *next = paction->next; delete paction; paction = next; } delete [] originalColumn_; delete [] originalRow_; paction_=NULL; originalColumn_=NULL; originalRow_=NULL; delete [] rowObjective_; rowObjective_=NULL; } /* This version of presolve returns a pointer to a new presolved model. NULL if infeasible */ ClpSimplex * ClpPresolve::presolvedModel(ClpSimplex & si, double feasibilityTolerance, bool keepIntegers, int numberPasses, bool dropNames, bool doRowObjective) { // Check matrix if (!si.clpMatrix()->allElementsInRange(&si,si.getSmallElementValue(), 1.0e20)) return NULL; else return gutsOfPresolvedModel(&si,feasibilityTolerance,keepIntegers,numberPasses,dropNames, doRowObjective); } #ifndef CLP_NO_STD /* This version of presolve updates model and saves original data to file. Returns non-zero if infeasible */ int ClpPresolve::presolvedModelToFile(ClpSimplex &si,std::string fileName, double feasibilityTolerance, bool keepIntegers, int numberPasses, bool doRowObjective) { // Check matrix if (!si.clpMatrix()->allElementsInRange(&si,si.getSmallElementValue(), 1.0e20)) return 2; saveFile_=fileName; si.saveModel(saveFile_.c_str()); ClpSimplex * model = gutsOfPresolvedModel(&si,feasibilityTolerance,keepIntegers,numberPasses,true, doRowObjective); if (model==&si) { return 0; } else { si.restoreModel(saveFile_.c_str()); remove(saveFile_.c_str()); return 1; } } #endif // Return pointer to presolved model ClpSimplex * ClpPresolve::model() const { return presolvedModel_; } // Return pointer to original model ClpSimplex * ClpPresolve::originalModel() const { return originalModel_; } void ClpPresolve::postsolve(bool updateStatus) { // Return at once if no presolved model if (!presolvedModel_) return; // Messages CoinMessages messages = originalModel_->coinMessages(); if (!presolvedModel_->isProvenOptimal()) { presolvedModel_->messageHandler()->message(COIN_PRESOLVE_NONOPTIMAL, messages) <getNumCols(); int nrows = presolvedModel_->getNumRows(); double * acts=NULL; double * sol =NULL; unsigned char * rowstat=NULL; unsigned char * colstat = NULL; #ifndef CLP_NO_STD if (saveFile_=="") { #endif // reality check assert(ncols0==originalModel_->getNumCols()); assert(nrows0==originalModel_->getNumRows()); acts = originalModel_->primalRowSolution(); sol = originalModel_->primalColumnSolution(); if (updateStatus) { // postsolve does not know about fixed int i; for (i=0;igetColumnStatus(i)==ClpSimplex::isFixed) presolvedModel_->setColumnStatus(i,ClpSimplex::atLowerBound); } unsigned char *status = originalModel_->statusArray(); if (!status) { originalModel_->createStatus(); status = originalModel_->statusArray(); } rowstat = status + ncols0; colstat = status; memcpy(colstat, presolvedModel_->statusArray(), ncols); memcpy(rowstat, presolvedModel_->statusArray()+ncols, nrows); } #ifndef CLP_NO_STD } else { // from file acts = new double[nrows0]; sol = new double[ncols0]; CoinZeroN(acts,nrows0); CoinZeroN(sol,ncols0); if (updateStatus) { unsigned char *status = new unsigned char [nrows0+ncols0]; rowstat = status + ncols0; colstat = status; memcpy(colstat, presolvedModel_->statusArray(), ncols); memcpy(rowstat, presolvedModel_->statusArray()+ncols, nrows); } } #endif // CoinPostsolveMatrix object assumes ownership of sol, acts, colstat; // will be deleted by ~CoinPostsolveMatrix. delete[] operations below // cause duplicate free. In case where saveFile == "", as best I can see // arrays are owned by originalModel_. fix is to // clear fields in prob to avoid delete[] in ~CoinPostsolveMatrix. CoinPostsolveMatrix prob(presolvedModel_, ncols0, nrows0, nelems0, presolvedModel_->getObjSense(), // end prepost sol, acts, colstat, rowstat); postsolve(prob); #ifndef CLP_NO_STD if (saveFile_!="") { // From file assert (originalModel_==presolvedModel_); originalModel_->restoreModel(saveFile_.c_str()); remove(saveFile_.c_str()); memcpy(originalModel_->primalRowSolution(),acts,nrows0*sizeof(double)); // delete [] acts; memcpy(originalModel_->primalColumnSolution(),sol,ncols0*sizeof(double)); // delete [] sol; if (updateStatus) { memcpy(originalModel_->statusArray(),colstat,nrows0+ncols0); // delete [] colstat; } } else { #endif prob.sol_ = 0 ; prob.acts_ = 0 ; prob.colstat_ = 0 ; #ifndef CLP_NO_STD } #endif // put back duals memcpy(originalModel_->dualRowSolution(),prob.rowduals_, nrows_*sizeof(double)); double maxmin = originalModel_->getObjSense(); if (maxmin<0.0) { // swap signs int i; double * pi = originalModel_->dualRowSolution(); for (i=0;idualColumnSolution(), originalModel_->objectiveAsObject()->gradient(originalModel_, originalModel_->primalColumnSolution(), offset,true),ncols_*sizeof(double)); originalModel_->transposeTimes(-1.0, originalModel_->dualRowSolution(), originalModel_->dualColumnSolution()); memset(originalModel_->primalRowSolution(),0,nrows_*sizeof(double)); originalModel_->times(1.0,originalModel_->primalColumnSolution(), originalModel_->primalRowSolution()); originalModel_->checkSolutionInternal(); // Messages presolvedModel_->messageHandler()->message(COIN_PRESOLVE_POSTSOLVE, messages) <objectiveValue() <sumDualInfeasibilities() <numberDualInfeasibilities() <sumPrimalInfeasibilities() <numberPrimalInfeasibilities() <objectiveValue_=objectiveValue_; originalModel_->setNumberIterations(presolvedModel_->numberIterations()); if (!presolvedModel_->status()) { if (!originalModel_->numberDualInfeasibilities()&& !originalModel_->numberPrimalInfeasibilities()) { originalModel_->setProblemStatus( 0); } else { originalModel_->setProblemStatus( -1); // Say not optimal after presolve originalModel_->setSecondaryStatus(7); presolvedModel_->messageHandler()->message(COIN_PRESOLVE_NEEDS_CLEANING, messages) <setProblemStatus( presolvedModel_->status()); } #ifndef CLP_NO_STD if (saveFile_!="") presolvedModel_=NULL; #endif } // return pointer to original columns const int * ClpPresolve::originalColumns() const { return originalColumn_; } // return pointer to original rows const int * ClpPresolve::originalRows() const { return originalRow_; } // Set pointer to original model void ClpPresolve::setOriginalModel(ClpSimplex * model) { originalModel_=model; } #if 0 // A lazy way to restrict which transformations are applied // during debugging. static int ATOI(const char *name) { return true; #if PRESOLVE_DEBUG || PRESOLVE_SUMMARY if (getenv(name)) { int val = atoi(getenv(name)); printf("%s = %d\n", name, val); return (val); } else { if (strcmp(name,"off")) return (true); else return (false); } #else return (true); #endif } #endif //#define PRESOLVE_DEBUG 1 #if PRESOLVE_DEBUG void check_sol(CoinPresolveMatrix *prob,double tol) { double *colels = prob->colels_; int *hrow = prob->hrow_; int *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int *hinrow = prob->hinrow_; int ncols = prob->ncols_; double * csol = prob->sol_; double * acts = prob->acts_; double * clo = prob->clo_; double * cup = prob->cup_; int nrows = prob->nrows_; double * rlo = prob->rlo_; double * rup = prob->rup_; int colx; double * rsol = new double[nrows]; memset(rsol,0,nrows*sizeof(double)); for (colx = 0; colx < ncols; ++colx) { if (1) { CoinBigIndex k = mcstrt[colx]; int nx = hincol[colx]; double solutionValue = csol[colx]; for (int i=0; icup[colx]+tol) { printf("high CSOL: %d - %g %g %g\n", colx, clo[colx], csol[colx], cup[colx]); } } } int rowx; for (rowx = 0; rowx < nrows; ++rowx) { if (hinrow[rowx]) { if (fabs(rsol[rowx]-acts[rowx])>tol) printf("inacc RSOL: %d - %g %g (acts_ %g) %g\n", rowx, rlo[rowx], rsol[rowx], acts[rowx], rup[rowx]); if (rsol[rowx]rup[rowx]+tol ) { printf("high RSOL: %d - %g %g %g\n", rowx, rlo[rowx], rsol[rowx], rup[rowx]); } } } delete [] rsol; } #endif // This is the presolve loop. // It is a separate virtual function so that it can be easily // customized by subclassing CoinPresolve. const CoinPresolveAction *ClpPresolve::presolve(CoinPresolveMatrix *prob) { // Messages CoinMessages messages = CoinMessage(prob->messages().language()); paction_ = 0; prob->status_=0; // say feasible paction_ = make_fixed(prob, paction_); // if integers then switch off dual stuff // later just do individually bool doDualStuff = (presolvedModel_->integerInformation()==NULL); // but allow in some cases if ((presolveActions_&512)!=0) doDualStuff=true; if (prob->anyProhibited()) doDualStuff=false; if (!doDual()) doDualStuff=false; #if PRESOLVE_CONSISTENCY // presolve_links_ok(prob->rlink_, prob->mrstrt_, prob->hinrow_, prob->nrows_); presolve_links_ok(prob,false,true) ; #endif if (!prob->status_) { bool slackSingleton = doSingletonColumn(); slackSingleton = false; const bool slackd = doSingleton(); const bool doubleton = doDoubleton(); const bool tripleton = doTripleton(); const bool forcing = doForcing(); const bool ifree = doImpliedFree(); const bool zerocost = doTighten(); const bool dupcol = doDupcol(); const bool duprow = doDuprow(); const bool dual = doDualStuff; // some things are expensive so just do once (normally) int i; // say look at all if (!prob->anyProhibited()) { for (i=0;irowsToDo_[i]=i; prob->numberRowsToDo_=nrows_; for (i=0;icolsToDo_[i]=i; prob->numberColsToDo_=ncols_; } else { // some stuff must be left alone prob->numberRowsToDo_=0; for (i=0;irowProhibited(i)) prob->rowsToDo_[prob->numberRowsToDo_++]=i; prob->numberColsToDo_=0; for (i=0;icolProhibited(i)) prob->colsToDo_[prob->numberColsToDo_++]=i; } int iLoop; #if PRESOLVE_DEBUG check_sol(prob,1.0e0); #endif if (dupcol) { //paction_ = dupcol_action::presolve(prob, paction_); } if ((presolveActions_&16384)!=0) prob->setPresolveOptions(prob->presolveOptions()|16384); // Check number rows dropped int lastDropped=0; prob->pass_=0; for (iLoop=0;iLoopstartTime_); #ifdef PRESOLVE_SUMMARY printf("Starting major pass %d\n",iLoop+1); #endif const CoinPresolveAction * const paction0 = paction_; // look for substitutions with no fill int fill_level=2; //fill_level=10; //printf("** fill_level == 10 !\n"); int whichPass=0; while (1) { whichPass++; prob->pass_++; const CoinPresolveAction * const paction1 = paction_; if (slackd) { bool notFinished = true; while (notFinished) paction_ = slack_doubleton_action::presolve(prob, paction_, notFinished); if (prob->status_) break; } if (dual&&whichPass==1) { // this can also make E rows so do one bit here paction_ = remove_dual_action::presolve(prob, paction_); if (prob->status_) break; } if (doubleton) { paction_ = doubleton_action::presolve(prob, paction_); if (prob->status_) break; } if (tripleton) { paction_ = tripleton_action::presolve(prob, paction_); if (prob->status_) break; } if (zerocost) { paction_ = do_tighten_action::presolve(prob, paction_); if (prob->status_) break; } if (forcing) { paction_ = forcing_constraint_action::presolve(prob, paction_); if (prob->status_) break; } if (ifree&&(whichPass%5)==1) { paction_ = implied_free_action::presolve(prob, paction_,fill_level); if (prob->status_) break; } #if PRESOLVE_DEBUG check_sol(prob,1.0e0); #endif #if PRESOLVE_CONSISTENCY // presolve_links_ok(prob->rlink_, prob->mrstrt_, prob->hinrow_, // prob->nrows_); presolve_links_ok(prob,false,true) ; #endif //#if PRESOLVE_DEBUG // presolve_no_zeros(prob->mcstrt_, prob->colels_, prob->hincol_, // prob->ncols_); //#endif //#if PRESOLVE_CONSISTENCY // prob->consistent(); //#endif #if PRESOLVE_CONSISTENCY presolve_no_zeros(prob,true,false) ; presolve_consistent(prob,true) ; #endif // set up for next pass // later do faster if many changes i.e. memset and memcpy prob->numberRowsToDo_ = prob->numberNextRowsToDo_; int kcheck; bool found=false; kcheck=-1; for (i=0;inumberNextRowsToDo_;i++) { int index = prob->nextRowsToDo_[i]; prob->unsetRowChanged(index); prob->rowsToDo_[i] = index; if (index==kcheck) { printf("row %d on list after pass %d\n",kcheck, whichPass); found=true; } } if (!found&&kcheck>=0) prob->rowsToDo_[prob->numberRowsToDo_++]=kcheck; prob->numberNextRowsToDo_=0; prob->numberColsToDo_ = prob->numberNextColsToDo_; kcheck=-1; found=false; for (i=0;inumberNextColsToDo_;i++) { int index = prob->nextColsToDo_[i]; prob->unsetColChanged(index); prob->colsToDo_[i] = index; if (index==kcheck) { printf("col %d on list after pass %d\n",kcheck, whichPass); found=true; } } if (!found&&kcheck>=0) prob->colsToDo_[prob->numberColsToDo_++]=kcheck; prob->numberNextColsToDo_=0; if (paction_ == paction1&&fill_level>0) break; } // say look at all int i; if (!prob->anyProhibited()) { for (i=0;irowsToDo_[i]=i; prob->numberRowsToDo_=nrows_; for (i=0;icolsToDo_[i]=i; prob->numberColsToDo_=ncols_; } else { // some stuff must be left alone prob->numberRowsToDo_=0; for (i=0;irowProhibited(i)) prob->rowsToDo_[prob->numberRowsToDo_++]=i; prob->numberColsToDo_=0; for (i=0;icolProhibited(i)) prob->colsToDo_[prob->numberColsToDo_++]=i; } // now expensive things // this caused world.mps to run into numerical difficulties #ifdef PRESOLVE_SUMMARY printf("Starting expensive\n"); #endif if (dual) { int itry; for (itry=0;itry<5;itry++) { paction_ = remove_dual_action::presolve(prob, paction_); if (prob->status_) break; const CoinPresolveAction * const paction2 = paction_; if (ifree) { //int fill_level=0; // switches off substitution paction_ = implied_free_action::presolve(prob, paction_,fill_level); if (prob->status_) break; } if (paction_ == paction2) break; } } else if (ifree) { // just free int fill_level=0; // switches off substitution paction_ = implied_free_action::presolve(prob, paction_,fill_level); if (prob->status_) break; } #if PRESOLVE_DEBUG check_sol(prob,1.0e0); #endif if (dupcol) { // maybe allow integer columns to be checked if ((presolveActions_&512)!=0) prob->setPresolveOptions(prob->presolveOptions()|1); paction_ = dupcol_action::presolve(prob, paction_); if (prob->status_) break; } #if PRESOLVE_DEBUG check_sol(prob,1.0e0); #endif if (duprow) { paction_ = duprow_action::presolve(prob, paction_); if (prob->status_) break; } #if PRESOLVE_DEBUG check_sol(prob,1.0e0); #endif bool stopLoop=false; { int * hinrow = prob->hinrow_; int numberDropped=0; for (i=0;imessageHandler()->message(COIN_PRESOLVE_PASS, messages) <status_) { paction_ = drop_zero_coefficients(prob, paction_); #if PRESOLVE_DEBUG check_sol(prob,1.0e0); #endif paction_ = drop_empty_cols_action::presolve(prob, paction_); paction_ = drop_empty_rows_action::presolve(prob, paction_); #if PRESOLVE_DEBUG check_sol(prob,1.0e0); #endif } if (prob->status_) { if (prob->status_==1) prob->messageHandler()->message(COIN_PRESOLVE_INFEAS, messages) <feasibilityTolerance_ <status_==2) prob->messageHandler()->message(COIN_PRESOLVE_UNBOUND, messages) <messageHandler()->message(COIN_PRESOLVE_INFEASUNBOUND, messages) <name()); #endif paction->postsolve(&prob); #if PRESOLVE_DEBUG { int nr=0; int i; for (i=0;i0) { presolve_check_nbasic(&prob) ; presolve_check_sol(&prob,2,2,1) ; } #endif paction = paction->next; #if PRESOLVE_DEBUG // check_djs(&prob); if (checkit>0) presolve_check_reduced_costs(&prob) ; #endif } #if PRESOLVE_DEBUG if (prob.colstat_) { presolve_check_nbasic(&prob) ; presolve_check_sol(&prob,2,2,1) ; } #endif #undef PRESOLVE_DEBUG #if 0 && PRESOLVE_DEBUG for (i=0; i 1e10) printf("!!!%d %g\n", i, sol[i]); } #endif #if 0 && PRESOLVE_DEBUG // debug check: make sure we ended up with same original matrix { int identical = 1; for (int i=0; imcstrt0[i+1] - &prob->mcstrt0[i]); CoinBigIndex kcs0 = &prob->mcstrt0[i]; CoinBigIndex kcs = mcstrt[i]; int n = hincol[i]; for (int k=0; khrow0[kcs0+k], kcs, kcs+n, hrow); if (k1 == kcs+n) { printf("ROW %d NOT IN COL %d\n", &prob->hrow0[kcs0+k], i); abort(); } if (colels[k1] != &prob->dels0[kcs0+k]) printf("BAD COLEL[%d %d %d]: %g\n", k1, i, &prob->hrow0[kcs0+k], colels[k1] - &prob->dels0[kcs0+k]); if (kcs0+k != k1) identical=0; } } printf("identical? %d\n", identical); } #endif } static inline double getTolerance(const ClpSimplex *si, ClpDblParam key) { double tol; if (! si->getDblParam(key, tol)) { CoinPresolveAction::throwCoinError("getDblParam failed", "CoinPrePostsolveMatrix::CoinPrePostsolveMatrix"); } return (tol); } // Assumptions: // 1. nrows>=m.getNumRows() // 2. ncols>=m.getNumCols() // // In presolve, these values are equal. // In postsolve, they may be inequal, since the reduced problem // may be smaller, but we need room for the large problem. // ncols may be larger than si.getNumCols() in postsolve, // this at that point si will be the reduced problem, // but we need to reserve enough space for the original problem. CoinPrePostsolveMatrix::CoinPrePostsolveMatrix(const ClpSimplex * si, int ncols_in, int nrows_in, CoinBigIndex nelems_in, double bulkRatio) : ncols_(si->getNumCols()), nrows_(si->getNumRows()), nelems_(si->getNumElements()), ncols0_(ncols_in), nrows0_(nrows_in), bulkRatio_(bulkRatio), mcstrt_(new CoinBigIndex[ncols_in+1]), hincol_(new int[ncols_in+1]), cost_(new double[ncols_in]), clo_(new double[ncols_in]), cup_(new double[ncols_in]), rlo_(new double[nrows_in]), rup_(new double[nrows_in]), originalColumn_(new int[ncols_in]), originalRow_(new int[nrows_in]), ztolzb_(getTolerance(si, ClpPrimalTolerance)), ztoldj_(getTolerance(si, ClpDualTolerance)), maxmin_(si->getObjSense()), sol_(NULL), rowduals_(NULL), acts_(NULL), rcosts_(NULL), colstat_(NULL), rowstat_(NULL), handler_(NULL), defaultHandler_(false), messages_() { bulk0_ = (CoinBigIndex) (bulkRatio_*nelems_in); hrow_ = new int [bulk0_]; colels_ = new double[bulk0_]; si->getDblParam(ClpObjOffset,originalOffset_); int ncols = si->getNumCols(); int nrows = si->getNumRows(); setMessageHandler(si->messageHandler()) ; ClpDisjointCopyN(si->getColLower(), ncols, clo_); ClpDisjointCopyN(si->getColUpper(), ncols, cup_); //ClpDisjointCopyN(si->getObjCoefficients(), ncols, cost_); double offset; ClpDisjointCopyN(si->objectiveAsObject()->gradient(si,si->getColSolution(),offset,true), ncols, cost_); ClpDisjointCopyN(si->getRowLower(), nrows, rlo_); ClpDisjointCopyN(si->getRowUpper(), nrows, rup_); int i; for (i=0;i= 0; --i) { if (start[i+1] - start[i] != length[i]) break; } return (! (i >= 0)); } } #if PRESOLVE_DEBUG static void matrix_bounds_ok(const double *lo, const double *up, int n) { int i; for (i=0; igetNumRows() ; // Set up change bits etc rowChanged_ = new unsigned char[nrows_]; memset(rowChanged_,0,nrows_); colChanged_ = new unsigned char[ncols_]; memset(colChanged_,0,ncols_); CoinPackedMatrix * m = si->matrix(); // The coefficient matrix is a big hunk of stuff. // Do the copy here to try to avoid running out of memory. const CoinBigIndex * start = m->getVectorStarts(); const int * length = m->getVectorLengths(); const int * row = m->getIndices(); const double * element = m->getElements(); int icol,nel=0; mcstrt_[0]=0; for (icol=0;icolgetVectorLengths(),ncols_, hincol_); // same thing for row rep CoinPackedMatrix * mRow = new CoinPackedMatrix(); mRow->reverseOrderedCopyOf(*m); mRow->removeGaps(); mRow->setExtraGap(0.0); // Now get rid of matrix si->createEmptyMatrix(); double * el = mRow->getMutableElements(); int * ind = mRow->getMutableIndices(); CoinBigIndex * strt = mRow->getMutableVectorStarts(); int * len = mRow->getMutableVectorLengths(); // Do carefully to save memory rowels_ = new double[bulk0_]; ClpDisjointCopyN(el, nelems_, rowels_); mRow->nullElementArray(); delete [] el; hcol_ = new int[bulk0_]; ClpDisjointCopyN(ind, nelems_, hcol_); mRow->nullIndexArray(); delete [] ind; mrstrt_ = new CoinBigIndex[nrows_in+1]; ClpDisjointCopyN(strt, nrows_, mrstrt_); mRow->nullStartArray(); mrstrt_[nrows_] = nelems_; delete [] strt; hinrow_ = new int[nrows_in+1]; ClpDisjointCopyN(len, nrows_, hinrow_); delete mRow; if (si->integerInformation()) { memcpy(integerType_,si->integerInformation(),ncols_*sizeof(char)); } else { ClpFillN(integerType_, ncols_, (unsigned char) 0); } #ifndef SLIM_CLP #ifndef NO_RTTI ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(si->objectiveAsObject())); #else ClpQuadraticObjective * quadraticObj = NULL; if (si->objectiveAsObject()->type()==2) quadraticObj = (static_cast< ClpQuadraticObjective*>(si->objectiveAsObject())); #endif #endif // Set up prohibited bits if needed if (nonLinearValue) { anyProhibited_ = true; for (icol=0;icolquadraticObjective(); //const int * columnQuadratic = quadratic->getIndices(); //const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts(); const int * columnQuadraticLength = quadratic->getVectorLengths(); //double * quadraticElement = quadratic->getMutableElements(); int numberColumns = quadratic->getNumCols(); anyProhibited_ = true; for (int iColumn=0;iColumnprimalColumnSolution(),ncols_*sizeof(double));; acts_ = new double [nrows_]; memcpy(acts_,si->primalRowSolution(),nrows_*sizeof(double)); if (!si->statusArray()) si->createStatus(); colstat_ = new unsigned char [nrows_+ncols_]; memcpy(colstat_,si->statusArray(), (nrows_+ncols_)*sizeof(unsigned char)); rowstat_ = colstat_+ncols_; } // the original model's fields are now unneeded - free them si->resize(0,0); #if PRESOLVE_DEBUG matrix_bounds_ok(rlo_, rup_, nrows_); matrix_bounds_ok(clo_, cup_, ncols_); #endif #if 0 for (i=0; iloadProblem(ncols_, nrows_, mcstrt_, hrow_, colels_, hincol_, clo_, cup_, cost_, rlo_, rup_); //delete [] si->integerInformation(); int numberIntegers=0; for (int i=0; icopyInIntegerInformation((const char *) integerType_); else si->copyInIntegerInformation(NULL); #if PRESOLVE_SUMMARY printf("NEW NCOL/NROW/NELS: %d(-%d) %d(-%d) %d(-%d)\n", ncols_, ncols0-ncols_, nrows_, nrows0-nrows_, si->getNumElements(), nelems0-si->getNumElements()); #endif si->setDblParam(ClpObjOffset,originalOffset_-dobias_); } //////////////// POSTSOLVE CoinPostsolveMatrix::CoinPostsolveMatrix(ClpSimplex* si, int ncols0_in, int nrows0_in, CoinBigIndex nelems0, double maxmin, // end prepost members double *sol_in, double *acts_in, unsigned char *colstat_in, unsigned char *rowstat_in) : CoinPrePostsolveMatrix(si, ncols0_in, nrows0_in, nelems0,2.0), free_list_(0), // link, free_list, maxlink maxlink_(bulk0_), link_(new int[/*maxlink*/ bulk0_]), cdone_(new char[ncols0_]), rdone_(new char[nrows0_in]) { bulk0_ = maxlink_ ; nrows_ = si->getNumRows() ; ncols_ = si->getNumCols() ; sol_=sol_in; rowduals_=NULL; acts_=acts_in; rcosts_=NULL; colstat_=colstat_in; rowstat_=rowstat_in; // this is the *reduced* model, which is probably smaller int ncols1 = ncols_ ; int nrows1 = nrows_ ; const CoinPackedMatrix * m = si->matrix(); const CoinBigIndex nelemsr = m->getNumElements(); if (m->getNumElements()&&!isGapFree(*m)) { // Odd - gaps CoinPackedMatrix mm(*m); mm.removeGaps(); mm.setExtraGap(0.0); ClpDisjointCopyN(mm.getVectorStarts(), ncols1, mcstrt_); CoinZeroN(mcstrt_+ncols1,ncols0_-ncols1); mcstrt_[ncols1] = nelems0; // ?? (should point to end of bulk store -- lh --) ClpDisjointCopyN(mm.getVectorLengths(),ncols1, hincol_); ClpDisjointCopyN(mm.getIndices(), nelemsr, hrow_); ClpDisjointCopyN(mm.getElements(), nelemsr, colels_); } else { // No gaps ClpDisjointCopyN(m->getVectorStarts(), ncols1, mcstrt_); CoinZeroN(mcstrt_+ncols1,ncols0_-ncols1); mcstrt_[ncols1] = nelems0; // ?? (should point to end of bulk store -- lh --) ClpDisjointCopyN(m->getVectorLengths(),ncols1, hincol_); ClpDisjointCopyN(m->getIndices(), nelemsr, hrow_); ClpDisjointCopyN(m->getElements(), nelemsr, colels_); } #if 0 && PRESOLVE_DEBUG presolve_check_costs(model, &colcopy); #endif // This determines the size of the data structure that contains // the matrix being postsolved. Links are taken from the free_list // to recreate matrix entries that were presolved away, // and links are added to the free_list when entries created during // presolve are discarded. There is never a need to gc this list. // Naturally, it should contain // exactly nelems0 entries "in use" when postsolving is done, // but I don't know whether the matrix could temporarily get // larger during postsolving. Substitution into more than two // rows could do that, in principle. I am being very conservative // here by reserving much more than the amount of space I probably need. // If this guess is wrong, check_free_list may be called. // int bufsize = 2*nelems0; memset(cdone_, -1, ncols0_); memset(rdone_, -1, nrows0_); rowduals_ = new double[nrows0_]; ClpDisjointCopyN(si->getRowPrice(), nrows1, rowduals_); rcosts_ = new double[ncols0_]; ClpDisjointCopyN(si->getReducedCost(), ncols1, rcosts_); if (maxmin<0.0) { // change so will look as if minimize int i; for (i=0;igetRowUpper(), nrows1, rup_); //ClpDisjointCopyN(si->getRowLower(), nrows1, rlo_); ClpDisjointCopyN(si->getColSolution(), ncols1, sol_); si->setDblParam(ClpObjOffset,originalOffset_); for (int j=0; jgetNumCols(); nrows_ = originalModel->getNumRows(); nelems_ = originalModel->getNumElements(); numberPasses_ = numberPasses; double maxmin = originalModel->getObjSense(); originalModel_ = originalModel; delete [] originalColumn_; originalColumn_ = new int[ncols_]; delete [] originalRow_; originalRow_ = new int[nrows_]; // and fill in case returns early int i; for (i=0;icoinMessages(); // Only go round 100 times even if integer preprocessing int totalPasses=100; while (result==-1) { #ifndef CLP_NO_STD // make new copy if (saveFile_=="") { #endif delete presolvedModel_; #ifndef CLP_NO_STD // So won't get names int lengthNames = originalModel->lengthNames(); originalModel->setLengthNames(0); #endif presolvedModel_ = new ClpSimplex(*originalModel); #ifndef CLP_NO_STD originalModel->setLengthNames(lengthNames); } else { presolvedModel_=originalModel; } presolvedModel_->dropNames(); #endif // drop integer information if wanted if (!keepIntegers) presolvedModel_->deleteIntegerInformation(); totalPasses--; double ratio=2.0; if (substitution_>3) ratio=substitution_; else if (substitution_==2) ratio=1.5; CoinPresolveMatrix prob(ncols_, maxmin, presolvedModel_, nrows_, nelems_,true,nonLinearValue_,ratio); prob.setMaximumSubstitutionLevel(substitution_); if (doRowObjective) memset(rowObjective_,0,nrows_*sizeof(double)); // See if we want statistics if ((presolveActions_&0x80000000)!=0) prob.statistics(); // make sure row solution correct { double *colels = prob.colels_; int *hrow = prob.hrow_; CoinBigIndex *mcstrt = prob.mcstrt_; int *hincol = prob.hincol_; int ncols = prob.ncols_; double * csol = prob.sol_; double * acts = prob.acts_; int nrows = prob.nrows_; int colx; memset(acts,0,nrows*sizeof(double)); for (colx = 0; colx < ncols; ++colx) { double solutionValue = csol[colx]; for (int i=mcstrt[colx]; iprimalColumnSolution(), prob.sol_,prob.ncols_*sizeof(double)); memcpy(presolvedModel_->primalRowSolution(), prob.acts_,prob.nrows_*sizeof(double)); memcpy(presolvedModel_->statusArray(), prob.colstat_,prob.ncols_*sizeof(unsigned char)); memcpy(presolvedModel_->statusArray()+prob.ncols_, prob.rowstat_,prob.nrows_*sizeof(unsigned char)); delete [] prob.sol_; delete [] prob.acts_; delete [] prob.colstat_; prob.sol_=NULL; prob.acts_=NULL; prob.colstat_=NULL; int ncolsNow = presolvedModel_->getNumCols(); memcpy(originalColumn_,prob.originalColumn_,ncolsNow*sizeof(int)); #ifndef SLIM_CLP #ifndef NO_RTTI ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(originalModel->objectiveAsObject())); #else ClpQuadraticObjective * quadraticObj = NULL; if (originalModel->objectiveAsObject()->type()==2) quadraticObj = (static_cast< ClpQuadraticObjective*>(originalModel->objectiveAsObject())); #endif if (quadraticObj) { // set up for subset char * mark = new char [ncols_]; memset(mark,0,ncols_); CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective(); //const int * columnQuadratic = quadratic->getIndices(); //const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts(); const int * columnQuadraticLength = quadratic->getVectorLengths(); //double * quadraticElement = quadratic->getMutableElements(); int numberColumns = quadratic->getNumCols(); ClpQuadraticObjective * newObj = new ClpQuadraticObjective(*quadraticObj, ncolsNow, originalColumn_); // and modify linear and check double * linear = newObj->linearObjective(); memcpy(linear,presolvedModel_->objective(),ncolsNow*sizeof(double)); int iColumn; for ( iColumn=0;iColumnquadraticObjective(); columnQuadraticLength = quadratic->getVectorLengths(); int numberColumns2 = quadratic->getNumCols(); for ( iColumn=0;iColumnsetObjective(newObj); delete newObj; // final check for ( iColumn=0;iColumngetNumRows(); memcpy(originalRow_,prob.originalRow_,nrowsNow*sizeof(int)); delete [] prob.originalRow_; prob.originalRow_=NULL; #ifndef CLP_NO_STD if (!dropNames&&originalModel->lengthNames()) { // Redo names int iRow; std::vector rowNames; rowNames.reserve(nrowsNow); for (iRow=0;iRowrowName(kRow)); } int iColumn; std::vector columnNames; columnNames.reserve(ncolsNow); for (iColumn=0;iColumncolumnName(kColumn)); } presolvedModel_->copyNames(rowNames,columnNames); } else { presolvedModel_->setLengthNames(0); } #endif if (rowObjective_) { int iRow; int k=-1; int nObj=0; for (iRow=0;iRowk); k=kRow; rowObjective_[iRow]=rowObjective_[kRow]; if (rowObjective_[iRow]) nObj++; } if (nObj) { printf("%d costed slacks\n",nObj); presolvedModel_->setRowObjective(rowObjective_); } } // now clean up integer variables. This can modify original int i; const char * information = presolvedModel_->integerInformation(); if (information) { int numberChanges=0; double * lower0 = originalModel_->columnLower(); double * upper0 = originalModel_->columnUpper(); double * lower = presolvedModel_->columnLower(); double * upper = presolvedModel_->columnUpper(); for (i=0;iupperValue) { numberChanges++; presolvedModel_->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, messages) <lowerValue0+1.0e-8) { lower0[iOriginal] = lowerValue; numberChanges++; } if (upperValuemessageHandler()->message(COIN_PRESOLVE_INTEGERMODS, messages) <0) { result = -1; // round again const CoinPresolveAction *paction = paction_; while (paction) { const CoinPresolveAction *next = paction->next; delete paction; paction = next; } paction_=NULL; } } } } else if (prob.status_) { // infeasible or unbounded result=1; originalModel->setProblemStatus(prob.status_); } else { // no changes - model needs restoring after Lou's changes #ifndef CLP_NO_STD if (saveFile_=="") { #endif delete presolvedModel_; presolvedModel_ = new ClpSimplex(*originalModel); // but we need to remove gaps ClpPackedMatrix* clpMatrix = dynamic_cast< ClpPackedMatrix*>(presolvedModel_->clpMatrix()); if (clpMatrix) { clpMatrix->getPackedMatrix()->removeGaps(); } #ifndef CLP_NO_STD } else { presolvedModel_=originalModel; } presolvedModel_->dropNames(); #endif // drop integer information if wanted if (!keepIntegers) presolvedModel_->deleteIntegerInformation(); result=2; } } if (result==0||result==2) { int nrowsAfter = presolvedModel_->getNumRows(); int ncolsAfter = presolvedModel_->getNumCols(); CoinBigIndex nelsAfter = presolvedModel_->getNumElements(); presolvedModel_->messageHandler()->message(COIN_PRESOLVE_STATS, messages) <