// Copyright (C) 2000, International Business Machines // Corporation and others. All Rights Reserved. #if defined(_MSC_VER) // Turn off compiler warning about long names # pragma warning(disable:4786) #endif #include #include #include #include #include #include #include "CglTreeInfo.hpp" #include "CoinHelperFunctions.hpp" #include "CoinSort.hpp" #include "CoinPackedMatrix.hpp" #include "CglStored.hpp" #include "OsiRowCut.hpp" // Default constructor CglTreeInfo::CglTreeInfo () : level(-1), pass(-1), formulation_rows(-1), options(0), inTree(false), strengthenRow(NULL),randomNumberGenerator(NULL) {} // Copy constructor CglTreeInfo::CglTreeInfo (const CglTreeInfo & rhs) : level(rhs.level), pass(rhs.pass), formulation_rows(rhs.formulation_rows), options(rhs.options), inTree(rhs.inTree), strengthenRow(rhs.strengthenRow), randomNumberGenerator(rhs.randomNumberGenerator) { } // Clone CglTreeInfo * CglTreeInfo::clone() const { return new CglTreeInfo(*this); } // Assignment operator CglTreeInfo & CglTreeInfo::operator=(const CglTreeInfo& rhs) { if (this != &rhs) { //CglCutGenerator::operator=(rhs); level = rhs.level; pass = rhs.pass; formulation_rows = rhs.formulation_rows; options = rhs.options; inTree = rhs.inTree; strengthenRow = rhs.strengthenRow; randomNumberGenerator = rhs.randomNumberGenerator; } return *this; } // Destructor CglTreeInfo::~CglTreeInfo () { } // Default constructor CglTreeProbingInfo::CglTreeProbingInfo () : CglTreeInfo(), fixEntry_(NULL), toZero_(NULL), toOne_(NULL), integerVariable_(NULL), backward_(NULL), fixingEntry_(NULL), numberVariables_(0), numberIntegers_(0), maximumEntries_(0), numberEntries_(-1) { } // Constructor from model CglTreeProbingInfo::CglTreeProbingInfo (const OsiSolverInterface * model) : CglTreeInfo(), fixEntry_(NULL), toZero_(NULL), toOne_(NULL), integerVariable_(NULL), backward_(NULL), fixingEntry_(NULL), numberVariables_(0), numberIntegers_(0), maximumEntries_(0), numberEntries_(-1) { numberVariables_=model->getNumCols(); // Too many ... but integerVariable_ = new int [numberVariables_]; backward_ = new int [numberVariables_]; int i; // Get integer types const char * columnType = model->getColType (true); for (i=0;iKEEP_CLIQUES) { int * sort = new int [numberCliques]; for (iClique=numberMatrixCliques;iCliqueallow) break; else nEqual++; } delete [] sort; int j=cliqueStart[numberMatrixCliques]; int put=j; int nClique=numberMatrixCliques; for (iClique=numberMatrixCliques;iCliqueallow) { copy=true; } else if (n==allow&&nEqual) { copy=true; nEqual--; } if (copy) { cliqueType[nClique++]=cliqueType[iClique]; for (;j(entry))+j); } // lexicographic sort int * which = new int [numberCliques]; int * position = new int [numberCliques]; int * sort = new int [numberCliques]; int * value = new int [numberCliques]; for (iClique=0;iCliqueiValue||position[kClique]jFirst) { // mark all apart from lowest number as duplicate and move on lastDone =jClique-1; for (jClique=jFirst;jClique<=lastDone;jClique++) { int kClique = which [jClique]; if (kClique!=iLowest) { value[kClique]=-2; nDup++; nSave += cliqueStart[kClique+1]-cliqueStart[kClique]; } } } } } if (printit) printf("%d duplicates\n",nDup); // Now see if any subset int nOut=0; for (int jClique=0;jCliquestatic_cast (sequenceInCliqueEntry(entry[cliqueStart[iClique+1]-1]))) { value[iClique]=numberIntegers; continue; } } if (iValuekValue) continue; // not a candidate // See if subset (remember duplicates have gone) if (cliqueStart[iClique+1]-position[iClique]> cliqueStart[kClique+1]-cliqueStart[kClique]) { // could be subset ? int offset = cliqueStart[iClique]-position[kClique]; int j; bool subset=true; // what about different fixes bool odd=false; for (j=cliqueStart[kClique]+1;jkColumn) { subset=false; } else { while (iColumn1) printf("clique %d is subset of %d\n",kClique,iClique); nOut++; break; } } } } if (nOut) { if(printit) printf("Can get rid of %d cliques\n",nOut); // make new copy int nNewC=numberCliques-nOut; int size = cliqueStart[numberCliques]-nSave; int n=0; int * start = new int [nNewC+1]; char * type = new char [nNewC]; start[0]=0; cliqueEntry * entryC = new cliqueEntry [size]; int nel=0; allNew = true; for (int jClique=0;jClique=numberLastTime) allNew=false; int nn=cliqueStart[kClique+1]-cliqueStart[kClique]; memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(cliqueEntry)); nel += nn; type[n++]=cliqueType[kClique]; start[n]=nel; } } int nM=n; for (int jClique=0;jClique=numberMatrixCliques) { if (kClique>=numberLastTime) allNew=false; int nn=cliqueStart[kClique+1]-cliqueStart[kClique]; memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(cliqueEntry)); nel += nn; type[n++]=cliqueType[kClique]; start[n]=nel; } } // move numberCliques=n; numberMatrixCliques=nM; delete [] cliqueStart; cliqueStart=start; delete [] entry; entry = entryC; delete [] cliqueType; cliqueType = type; if (printit>1) { for (int jClique=0;jCliquegetIndices(); const double * elementByRow = rowCopy->getElements(); const CoinBigIndex * rowStart = rowCopy->getVectorStarts(); const int * rowLength = rowCopy->getVectorLengths(); const double * lower = si.getColLower(); const double * upper = si.getColUpper(); const double * rowLower = si.getRowLower(); const double * rowUpper = si.getRowUpper(); for (int iPass=0;iPass<2;iPass++) { if (iPass) { maximumCliques=numberCliques; maximumEntries=numberEntries; cliqueStart = new int [numberCliques+1]; cliqueStart[0]=0; entry = new cliqueEntry [numberEntries]; cliqueType = new char [numberCliques]; whichClique = new int [numberEntries]; numberCliques=0; numberEntries=0; } #if 1 for (iRow=0;iRow0.0) { assert (numberP1 (floor(upperValue+1.0e-5)); int iLower = static_cast (ceil(lowerValue-1.0e-5)); int state=0; if (upperValue<1.0e6) { if (iUpper==1-numberM1) state=1; else if (iUpper==-numberM1) state=2; else if (iUpper<-numberM1) state=3; if (fabs(static_cast (iUpper)-upperValue)>1.0e-9) state =-1; } if (!state&&lowerValue>-1.0e6) { if (-iLower==1-numberP1) state=-1; else if (-iLower==-numberP1) state=-2; else if (-iLower<-numberP1) state=-3; if (fabs(static_cast (iLower)-lowerValue)>1.0e-9) state =-1; } if (numberP1+numberM1<2) state=-1; if (good&&state>0) { if (abs(state)==3) { // infeasible printf("FFF Infeasible\n");; //feasible=false; break; } else if (abs(state)==2) { // we can fix all //numberFixed += numberP1+numberM1; printf("FFF can fix %d\n",numberP1+numberM1); } else { for (j=0;j (numberIntegers_);iColumn++) { int j; for ( j=toZero_[iColumn];j (sequenceInCliqueEntry(entry[j])); if (oneFixesInCliqueEntry(entry[j])) { oneCount[iColumn]++; } else { zeroCount[iColumn]++; } } } int j; zeroStart[0]=0; cliqueStart[0]=0; for (j=0;j (sequenceInCliqueEntry(entry[j])); if (oneFixesInCliqueEntry(entry[j])) { int k=oneCount[iColumn]; oneCount[iColumn]++; int put = oneStart[iColumn]+k; whichClique[put]=iClique; } else { int k=zeroCount[iColumn]; zeroCount[iColumn]++; int put = zeroStart[iColumn]+k; whichClique[put]=iClique; } } } nStrengthen=0; int numberEntries=cliqueStart[numberCliques]; int maximumEntries=numberEntries; int maximumCliques=numberCliques; for (iColumn=0;iColumniColumn&&!mark[jColumn]) { mark[jColumn]=1; whichP[n++]=jColumn; assert (nmaximumEntries) { maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100); cliqueEntry * temp = new cliqueEntry [maximumEntries]; memcpy(temp,entry,numberEntries*sizeof(cliqueEntry)); delete [] entry; entry=temp; int * tempI = new int [maximumEntries]; memcpy(tempI,whichClique,numberEntries*sizeof(int)); delete [] whichClique; whichClique=tempI; } if (numberCliques==maximumCliques) { maximumCliques = (maximumCliques*12)/10+100; int * temp = new int [maximumCliques+1]; memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int)); delete [] cliqueStart; cliqueStart=temp; char * tempT = new char [maximumCliques]; memcpy(tempT,cliqueType,numberCliques); delete [] cliqueType; cliqueType=tempT; } cliqueEntry eI; eI.fixes=0; setSequenceInCliqueEntry(eI,iColumn); setOneFixesInCliqueEntry(eI,false); entry[numberEntries++]=eI; whichM[0]=iColumn; int n=1; for (int i=cliqueStart[jClique];i(entry))+numberEntries-n); cliqueType[numberCliques]='S'; numberCliques++; cliqueStart[numberCliques]=numberEntries; } } for (i=0;iiColumn&&!mark[jColumn]) { mark[jColumn]=1; whichP[n++]=jColumn; assert (nmaximumEntries) { maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100); cliqueEntry * temp = new cliqueEntry [maximumEntries]; memcpy(temp,entry,numberEntries*sizeof(cliqueEntry)); delete [] entry; entry=temp; int * tempI = new int [maximumEntries]; memcpy(tempI,whichClique,numberEntries*sizeof(int)); delete [] whichClique; whichClique=tempI; } if (numberCliques==maximumCliques) { maximumCliques = (maximumCliques*12)/10+100; int * temp = new int [maximumCliques+1]; memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int)); delete [] cliqueStart; cliqueStart=temp; char * tempT = new char [maximumCliques]; memcpy(tempT,cliqueType,numberCliques); delete [] cliqueType; cliqueType=tempT; } cliqueEntry eI; eI.fixes=0; setSequenceInCliqueEntry(eI,iColumn); setOneFixesInCliqueEntry(eI,true); entry[numberEntries++]=eI; whichM[0]=iColumn; int n=1; for (int i=cliqueStart[jClique];i(entry))+numberEntries-n); cliqueType[numberCliques]='S'; numberCliques++; cliqueStart[numberCliques]=numberEntries; } } for (i=0;i1&&numberCliques-numberDeleted>5000)) nStrengthen=0; } delete [] count; delete [] whichCount; } #if 0 if (numberCliques>numberMatrixCliques) { // should keep as cliques and also use in branching ?? double * element = new double [numberIntegers_]; for (iClique=numberMatrixCliques;iCliqueaddCut(-COIN_DBL_MAX,rhs,n,whichP,element); } delete [] element; } #endif OsiSolverInterface * newSolver=NULL; if (numberCliques>numberMatrixCliques) { newSolver = si.clone(); // Delete all rows int * start = new int [ CoinMax(numberRows,numberCliques+1)]; int i; for (i=0;ideleteRows(numberRows,start); start[0]=0; int numberElements = cliqueStart[numberCliques]; int * column = new int [numberElements]; double * element = new double [numberElements]; double * lower = new double [numberCliques]; double * upper = new double [numberCliques]; numberElements=0; for (iClique=0;iCliqueaddRows(numberCliques,start,column,element,lower,upper); delete [] start; delete [] column; delete [] element; delete [] lower; delete [] upper; } delete [] mark; delete [] whichP; delete [] whichM; delete [] cliqueStart; delete [] entry; delete [] cliqueType; delete [] zeroStart; delete [] oneStart; delete [] zeroCount; delete [] oneCount; delete [] whichClique; return newSolver; } // Take action if cut generator can fix a variable (toValue -1 for down, +1 for up) bool CglTreeProbingInfo::fixes(int variable, int toValue, int fixedVariable,bool fixedToLower) { //printf("%d going to %d fixes %d at %g\n",variable,toValue,fixedVariable,fixedToValue); int intVariable = backward_[variable]; if (intVariable<0) // off as no longer in order FIX return true; // not 0-1 (well wasn't when constructor was called) int intFix = backward_[fixedVariable]; if (intFix<0) intFix = numberIntegers_+fixedVariable; // not 0-1 int fixedTo = fixedToLower ? 0 : 1; if (numberEntries_==maximumEntries_) { // See if taking too much memory if (maximumEntries_>=CoinMax(1000000,10*numberIntegers_)) return false; maximumEntries_ += 100 +maximumEntries_/2; cliqueEntry * temp1 = new cliqueEntry [maximumEntries_]; memcpy(temp1,fixEntry_,numberEntries_*sizeof(cliqueEntry)); delete [] fixEntry_; fixEntry_ = temp1; int * temp2 = new int [maximumEntries_]; memcpy(temp2,fixingEntry_,numberEntries_*sizeof(int)); delete [] fixingEntry_; fixingEntry_ = temp2; } cliqueEntry entry1; entry1.fixes=0; setOneFixesInCliqueEntry(entry1,fixedTo!=0); setSequenceInCliqueEntry(entry1,intFix); fixEntry_[numberEntries_] = entry1; assert (toValue==-1||toValue==1); assert (fixedTo==0||fixedTo==1); if (toValue<0) fixingEntry_[numberEntries_++] = intVariable << 1; else fixingEntry_[numberEntries_++] = (intVariable << 1) | 1; return true; } // Initalizes fixing arrays etc - returns true if we want to save info int CglTreeProbingInfo::initializeFixing(const OsiSolverInterface * model) { if (numberEntries_>=0) return 2; // already got arrays else if (numberEntries_==-2) return numberEntries_; delete [] fixEntry_; delete [] toZero_; delete [] toOne_; delete [] integerVariable_; delete [] backward_; delete [] fixingEntry_; numberVariables_=model->getNumCols(); // Too many ... but integerVariable_ = new int [numberVariables_]; backward_ = new int [numberVariables_]; numberIntegers_=0; int i; // Get integer types const char * columnType = model->getColType (true); for (i=0;i=0) { CoinSort_2( fixingEntry_, fixingEntry_+numberEntries_, fixEntry_); assert (!toZero_); toZero_ = new int [numberIntegers_+1]; toOne_ = new int [numberIntegers_]; toZero_[0]=0; int n=0; int put=0; for (int intVariable = 0;intVariable>1; int way = value &1; if (intVariable!=iVar||way) break; } if (n>last) { // sort assert (sizeof(int)==4); std::sort(reinterpret_cast (fixEntry_)+last, reinterpret_cast (fixEntry_)+n); cliqueEntry temp2; temp2.fixes=0; setSequenceInCliqueEntry(temp2,numberVariables_+1); for (int i=last;i>1; if (intVariable!=iVar) break; } if (n>last) { // sort assert (sizeof(int)==4); std::sort(reinterpret_cast (fixEntry_)+last, reinterpret_cast (fixEntry_)+n); cliqueEntry temp2; temp2.fixes=0; setSequenceInCliqueEntry(temp2,numberVariables_+1); for (int i=last;i (numberIntegers_);jColumn++) { int iColumn = integerVariable_[jColumn]; if (upper[iColumn]==0.0) { int j; for ( j=toZero_[jColumn];j=0); if (!value) { int j; for ( j=toZero_[jColumn];j (numberIntegers_);jColumn++) { int j; for ( j=iLast;j (numberIntegers_);jColumn++) { int iColumn = integerVariable_[jColumn]; assert (iColumn>=0&&iColumn=0&&kColumn=0&&kColumn0.00001) { OsiRowCut rc; int index[2]; double element[2]; index[0]=iColumn; element[0]=1.0; index[1]=kColumn; element[1]= -1.0; rc.setLb(-COIN_DBL_MAX); rc.setUb(0.0); rc.setRow(2,index,element,false); cs.insert(rc); } } else { if (value1+value2>1.00001) { OsiRowCut rc; int index[2]; double element[2]; index[0]=iColumn; element[0]=1.0; index[1]=kColumn; element[1]= 1.0; rc.setLb(-COIN_DBL_MAX); rc.setUb(1.0); rc.setRow(2,index,element,false); cs.insert(rc); } } } } } else if (upper[iColumn]==0.0) { for (int j=toZero_[jColumn];j=0&&kColumn=0&&kColumn