/* $Id: CoinStructuredModel.cpp 1373 2011-01-03 23:57:44Z lou $ */ // Copyright (C) 2008, International Business Machines // Corporation and others. All Rights Reserved. // This code is licensed under the terms of the Eclipse Public License (EPL). #include "CoinUtilsConfig.h" #include "CoinHelperFunctions.hpp" #include "CoinStructuredModel.hpp" #include "CoinSort.hpp" #include "CoinMpsIO.hpp" #include "CoinFloatEqual.hpp" //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- CoinStructuredModel::CoinStructuredModel () : CoinBaseModel(), numberRowBlocks_(0), numberColumnBlocks_(0), numberElementBlocks_(0), maximumElementBlocks_(0), blocks_(NULL), coinModelBlocks_(NULL), blockType_(NULL) { } /* Read a problem in MPS or GAMS format from the given filename. */ CoinStructuredModel::CoinStructuredModel(const char *fileName, int decomposeType, int maxBlocks) : CoinBaseModel(), numberRowBlocks_(0), numberColumnBlocks_(0), numberElementBlocks_(0), maximumElementBlocks_(0), blocks_(NULL), coinModelBlocks_(NULL), blockType_(NULL) { CoinModel coinModel(fileName,false); if (coinModel.numberRows()) { problemName_ = coinModel.getProblemName(); optimizationDirection_ = coinModel.optimizationDirection(); objectiveOffset_ = coinModel.objectiveOffset(); if (!decomposeType) { addBlock("row_master","column_master",coinModel); } else { const CoinPackedMatrix * matrix = coinModel.packedMatrix(); if (!matrix) coinModel.convertMatrix(); decompose(coinModel,decomposeType,maxBlocks); //addBlock("row_master","column_master",coinModel); } } } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- CoinStructuredModel::CoinStructuredModel (const CoinStructuredModel & rhs) : CoinBaseModel(rhs), numberRowBlocks_(rhs.numberRowBlocks_), numberColumnBlocks_(rhs.numberColumnBlocks_), numberElementBlocks_(rhs.numberElementBlocks_), maximumElementBlocks_(rhs.maximumElementBlocks_) { if (maximumElementBlocks_) { blocks_ = CoinCopyOfArray(rhs.blocks_,maximumElementBlocks_); for (int i=0;iclone(); blockType_ = CoinCopyOfArray(rhs.blockType_,maximumElementBlocks_); if (rhs.coinModelBlocks_) { coinModelBlocks_ = CoinCopyOfArray(rhs.coinModelBlocks_, maximumElementBlocks_); for (int i=0;iclone(); blockType_ = CoinCopyOfArray(rhs.blockType_,maximumElementBlocks_); if (rhs.coinModelBlocks_) { coinModelBlocks_ = CoinCopyOfArray(rhs.coinModelBlocks_, maximumElementBlocks_); for (int i=0;inumberRows(); for ( i=0;igetRowName(i); const char * bName = b->getRowName(i); bool good=true; if (aName) { if (!bName||strcmp(aName,bName)) good=false; } else if (bName) { good=false; } if (!good) break; } } else { n = a->numberColumns(); for ( i=0;igetColumnName(i); const char * bName = b->getColumnName(i); bool good=true; if (aName) { if (!bName||strcmp(aName,bName)) good=false; } else if (bName) { good=false; } if (!good) break; } } return (i==n); } // Add a row block name and number of rows int CoinStructuredModel::addRowBlock(int numberRows,const std::string &name) { int iRowBlock; for (iRowBlock=0;iRowBlocknumberElements(); } return numberElements; } // Return i'th block as CoinModel (or NULL) CoinModel * CoinStructuredModel::coinBlock(int i) const { CoinModel * block = dynamic_cast(blocks_[i]); if (block) return block; else if (coinModelBlocks_) return coinModelBlocks_[i]; else return NULL; } /* Return block as a CoinModel block and fill in info structure and update counts */ CoinModel * CoinStructuredModel::coinModelBlock(CoinModelBlockInfo & info) { // CoinStructuredModel int numberRows=this->numberRows(); int numberColumns =this-> numberColumns(); int numberRowBlocks=this->numberRowBlocks(); int numberColumnBlocks =this-> numberColumnBlocks(); int numberElementBlocks =this-> numberElementBlocks(); CoinBigIndex numberElements=this->numberElements(); // See what is needed double * rowLower = NULL; double * rowUpper = NULL; double * columnLower = NULL; double * columnUpper = NULL; double * objective = NULL; int * integerType = NULL; info = CoinModelBlockInfo(); CoinModel ** blocks = new CoinModel * [numberElementBlocks]; for (int iBlock=0;iBlock(blocks_[iBlock]); CoinModel * thisBlock; if (subModel) { thisBlock = subModel->coinModelBlock(thisInfo); fillInfo(thisInfo,subModel); setCoinModel(thisBlock,iBlock); } else { thisBlock = dynamic_cast(blocks_[iBlock]); assert (thisBlock); fillInfo(thisInfo,thisBlock); } blocks[iBlock]=thisBlock; if (thisInfo.rhs&&!info.rhs) { info.rhs=1; rowLower = new double [numberRows]; rowUpper = new double [numberRows]; CoinFillN(rowLower,numberRows,-COIN_DBL_MAX); CoinFillN(rowUpper,numberRows,COIN_DBL_MAX); } if (thisInfo.bounds&&!info.bounds) { info.bounds=1; columnLower = new double [numberColumns]; columnUpper = new double [numberColumns]; objective = new double [numberColumns]; CoinFillN(columnLower,numberColumns,0.0); CoinFillN(columnUpper,numberColumns,COIN_DBL_MAX); CoinFillN(objective,numberColumns,0.0); } if (thisInfo.integer&&!info.integer) { info.integer=1; integerType = new int [numberColumns]; CoinFillN(integerType,numberColumns,0); } if (thisInfo.rowName&&!info.rowName) { info.rowName=1; } if (thisInfo.columnName&&!info.columnName) { info.columnName=1; } } // Space for elements int * row = new int[numberElements]; int * column = new int[numberElements]; double * element = new double[numberElements]; numberElements=0; // Bases for blocks int * rowBase = new int[numberRowBlocks]; CoinFillN(rowBase,numberRowBlocks,-1); CoinModelBlockInfo * rowBlockInfo = new CoinModelBlockInfo [numberRowBlocks]; int * columnBase = new int[numberColumnBlocks]; CoinFillN(columnBase,numberColumnBlocks,-1); CoinModelBlockInfo * columnBlockInfo = new CoinModelBlockInfo [numberColumnBlocks]; for (int iBlock=0;iBlockgetRowBlock()); assert (iRowBlock>=0&&iRowBlocknumberRows(); else assert (rowBase[iRowBlock]==blocks[iBlock]->numberRows()); int iColumnBlock = columnBlock(blocks[iBlock]->getColumnBlock()); assert (iColumnBlock>=0&&iColumnBlocknumberColumns(); else assert (columnBase[iColumnBlock]==blocks[iBlock]->numberColumns()); } int n=0; for (int iBlock=0;iBlock=0); n+=k; } assert (n==numberRows); n=0; for (int iBlock=0;iBlock=0); n+=k; } assert (n==numberColumns); for (int iBlock=0;iBlockgetRowBlock()); int iRowBase = rowBase[iRowBlock]; int nRows = thisBlock->numberRows(); // could check if identical before error if (thisInfo.rhs) { assert (!rowBlockInfo[iRowBlock].rhs); rowBlockInfo[iRowBlock].rhs=1; memcpy(rowLower+iRowBase,thisBlock->rowLowerArray(), nRows*sizeof(double)); memcpy(rowUpper+iRowBase,thisBlock->rowUpperArray(), nRows*sizeof(double)); } int iColumnBlock = columnBlock(blocks[iBlock]->getColumnBlock()); int iColumnBase = columnBase[iColumnBlock]; int nColumns = thisBlock->numberColumns(); if (thisInfo.bounds) { assert (!columnBlockInfo[iColumnBlock].bounds); columnBlockInfo[iColumnBlock].bounds=1; memcpy(columnLower+iColumnBase,thisBlock->columnLowerArray(), nColumns*sizeof(double)); memcpy(columnUpper+iColumnBase,thisBlock->columnUpperArray(), nColumns*sizeof(double)); memcpy(objective+iColumnBase,thisBlock->objectiveArray(), nColumns*sizeof(double)); } if (thisInfo.integer) { assert (!columnBlockInfo[iColumnBlock].integer); columnBlockInfo[iColumnBlock].integer=1; memcpy(integerType+iColumnBase,thisBlock->integerTypeArray(), nColumns*sizeof(int)); } const CoinPackedMatrix * elementBlock = thisBlock->packedMatrix(); // get matrix data pointers const int * row2 = elementBlock->getIndices(); const CoinBigIndex * columnStart = elementBlock->getVectorStarts(); const double * elementByColumn = elementBlock->getElements(); const int * columnLength = elementBlock->getVectorLengths(); int n = elementBlock->getNumCols(); assert (elementBlock->isColOrdered()); for (int iColumn=0;iColumnsetColumnIsInteger(iColumn,integerType[iColumn]!=0); } } delete [] integerType; block->setObjectiveOffset(objectiveOffset()); if (info.rowName||info.columnName) { for (int iBlock=0;iBlockgetRowBlock()); int iRowBase = rowBase[iRowBlock]; if (thisInfo.rowName) { int numberItems = thisBlock->rowNames()->numberItems(); assert( thisBlock->numberRows()>=numberItems); if (numberItems) { const char *const * rowNames=thisBlock->rowNames()->names(); for (int i=0;isetRowName(i+iRowBase,name.c_str()); } } } int iColumnBlock = columnBlock(thisBlock->getColumnBlock()); int iColumnBase = columnBase[iColumnBlock]; if (thisInfo.columnName) { int numberItems = thisBlock->columnNames()->numberItems(); assert( thisBlock->numberColumns()>=numberItems); if (numberItems) { const char *const * columnNames=thisBlock->columnNames()->names(); for (int i=0;isetColumnName(i+iColumnBase,name.c_str()); } } } } } delete [] rowBase; delete [] columnBase; for (int iBlock=0;iBlock (blocks[iBlock])!= static_cast (blocks_[iBlock])) delete blocks[iBlock]; } delete [] blocks; return block; } // Sets given block into coinModelBlocks_ void CoinStructuredModel::setCoinModel(CoinModel * block, int iBlock) { if (!coinModelBlocks_) { coinModelBlocks_ = new CoinModel * [maximumElementBlocks_]; CoinZeroN(coinModelBlocks_,maximumElementBlocks_); } delete coinModelBlocks_[iBlock]; coinModelBlocks_[iBlock]=block; } // Refresh info in blockType_ void CoinStructuredModel::refresh(int iBlock) { fillInfo(blockType_[iBlock],coinBlock(iBlock)); } /* Fill in info structure and update counts Returns number of inconsistencies on border */ int CoinStructuredModel::fillInfo(CoinModelBlockInfo & info, const CoinModel * block) { int whatsSet = block->whatIsSet(); info.matrix = static_cast(((whatsSet&1)!=0) ? 1 : 0); info.rhs = static_cast(((whatsSet&2)!=0) ? 1 : 0); info.rowName = static_cast(((whatsSet&4)!=0) ? 1 : 0); info.integer = static_cast(((whatsSet&32)!=0) ? 1 : 0); info.bounds = static_cast(((whatsSet&8)!=0) ? 1 : 0); info.columnName = static_cast(((whatsSet&16)!=0) ? 1 : 0); int numberRows = block->numberRows(); int numberColumns = block->numberColumns(); // Which block int iRowBlock=addRowBlock(numberRows,block->getRowBlock()); info.rowBlock=iRowBlock; int iColumnBlock=addColumnBlock(numberColumns,block->getColumnBlock()); info.columnBlock=iColumnBlock; int numberErrors=0; CoinModelBlockInfo sumInfo=blockType_[numberElementBlocks_-1]; int iRhs=(sumInfo.rhs) ? numberElementBlocks_-1 : -1; int iRowName=(sumInfo.rowName) ? numberElementBlocks_-1 : -1; int iBounds=(sumInfo.bounds) ? numberElementBlocks_-1 : -1; int iColumnName=(sumInfo.columnName) ? numberElementBlocks_-1 : -1; int iInteger=(sumInfo.integer) ? numberElementBlocks_-1 : -1; for (int i=0;inumberRows()) numberErrors+=1000; if (blockType_[i].rhs) { if (iRhs<0) { iRhs=i; } else { // check const double * a = static_cast(blocks_[iRhs])->rowLowerArray(); const double * b = static_cast(blocks_[i])->rowLowerArray(); if (!sameValues(a,b,numberRows)) numberErrors++; a = static_cast(blocks_[iRhs])->rowUpperArray(); b = static_cast(blocks_[i])->rowUpperArray(); if (!sameValues(a,b,numberRows)) numberErrors++; } } if (blockType_[i].rowName) { if (iRowName<0) { iRowName=i; } else { // check if (!sameValues(static_cast(blocks_[iRowName]), static_cast(blocks_[i]),true)) numberErrors++; } } } if (iColumnBlock==blockType_[i].columnBlock) { if (numberColumns!=blocks_[i]->numberColumns()) numberErrors+=1000; if (blockType_[i].bounds) { if (iBounds<0) { iBounds=i; } else { // check const double * a = static_cast(blocks_[iBounds])->columnLowerArray(); const double * b = static_cast(blocks_[i])->columnLowerArray(); if (!sameValues(a,b,numberColumns)) numberErrors++; a = static_cast(blocks_[iBounds])->columnUpperArray(); b = static_cast(blocks_[i])->columnUpperArray(); if (!sameValues(a,b,numberColumns)) numberErrors++; a = static_cast(blocks_[iBounds])->objectiveArray(); b = static_cast(blocks_[i])->objectiveArray(); if (!sameValues(a,b,numberColumns)) numberErrors++; } } if (blockType_[i].columnName) { if (iColumnName<0) { iColumnName=i; } else { // check if (!sameValues(static_cast(blocks_[iColumnName]), static_cast(blocks_[i]),false)) numberErrors++; } } if (blockType_[i].integer) { if (iInteger<0) { iInteger=i; } else { // check const int * a = static_cast(blocks_[iInteger])->integerTypeArray(); const int * b = static_cast(blocks_[i])->integerTypeArray(); if (!sameValues(a,b,numberColumns)) numberErrors++; } } } } return numberErrors; } /* Fill in info structure and update counts */ void CoinStructuredModel::fillInfo(CoinModelBlockInfo & info, const CoinStructuredModel * block) { int numberRows = block->numberRows(); int numberColumns = block->numberColumns(); // Which block int iRowBlock=addRowBlock(numberRows,block->rowBlockName_); info.rowBlock=iRowBlock; int iColumnBlock=addColumnBlock(numberColumns,block->columnBlockName_); info.columnBlock=iColumnBlock; } /* add a block from a CoinModel without names*/ int CoinStructuredModel::addBlock(const std::string & rowBlock, const std::string & columnBlock, const CoinBaseModel & block) { CoinBaseModel * block2 = block.clone(); return addBlock(rowBlock,columnBlock,block2); } /* add a block using names */ int CoinStructuredModel::addBlock(const std::string & rowBlock, const std::string & columnBlock, const CoinPackedMatrix & matrix, const double * rowLower, const double * rowUpper, const double * columnLower, const double * columnUpper, const double * objective) { CoinModel * block = new CoinModel(); block->loadBlock(matrix,columnLower,columnUpper,objective, rowLower,rowUpper); return addBlock(rowBlock,columnBlock,block); } /* add a block from a CoinModel without names*/ int CoinStructuredModel::addBlock(const std::string & rowBlock, const std::string & columnBlock, CoinBaseModel * block) { if (numberElementBlocks_==maximumElementBlocks_) { maximumElementBlocks_ = 3*(maximumElementBlocks_+10)/2; CoinBaseModel ** temp = new CoinBaseModel * [maximumElementBlocks_]; memcpy(temp,blocks_,numberElementBlocks_*sizeof(CoinBaseModel *)); delete [] blocks_; blocks_ = temp; CoinModelBlockInfo * temp2 = new CoinModelBlockInfo [maximumElementBlocks_]; memcpy(temp2,blockType_,numberElementBlocks_*sizeof(CoinModelBlockInfo)); delete [] blockType_; blockType_ = temp2; if (coinModelBlocks_) { CoinModel ** temp = new CoinModel * [maximumElementBlocks_]; CoinZeroN(temp,maximumElementBlocks_); memcpy(temp,coinModelBlocks_,numberElementBlocks_*sizeof(CoinModel *)); delete [] coinModelBlocks_; coinModelBlocks_ = temp; } } blocks_[numberElementBlocks_++]=block; block->setRowBlock(rowBlock); block->setColumnBlock(columnBlock); int numberErrors=0; CoinModel * coinBlock = dynamic_cast(block); if (coinBlock) { // Convert matrix if (coinBlock->type()!=3) coinBlock->convertMatrix(); numberErrors=fillInfo(blockType_[numberElementBlocks_-1],coinBlock); } else { CoinStructuredModel * subModel = dynamic_cast(block); assert (subModel); CoinModel * blockX = subModel->coinModelBlock(blockType_[numberElementBlocks_-1]); fillInfo(blockType_[numberElementBlocks_-1],subModel); setCoinModel(blockX,numberElementBlocks_-1); } return numberErrors; } /* add a block from a CoinModel with names*/ int CoinStructuredModel::addBlock(const CoinBaseModel & block) { //inline const std::string & getRowBlock() const //abort(); return addBlock(block.getRowBlock(),block.getColumnBlock(), block); } /* Decompose a model specified as arrays + CoinPackedMatrix 1 - try D-W 2 - try Benders 3 - try Staircase Returns number of blocks or zero if no structure */ int CoinStructuredModel::decompose(const CoinPackedMatrix & matrix, const double * rowLower, const double * rowUpper, const double * columnLower, const double * columnUpper, const double * objective, int type,int maxBlocks, double objectiveOffset) { setObjectiveOffset(objectiveOffset); int numberBlocks=0; if (type==1) { // Try master at top and bottom bool goodDW=true; // get row copy CoinPackedMatrix rowCopy = matrix; rowCopy.reverseOrdering(); const int * row = matrix.getIndices(); const int * columnLength = matrix.getVectorLengths(); const CoinBigIndex * columnStart = matrix.getVectorStarts(); //const double * elementByColumn = matrix.getElements(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); //const double * elementByRow = rowCopy.getElements(); int numberRows = matrix.getNumRows(); int * rowBlock = new int[numberRows+1]; int iRow; // Row counts (maybe look at long rows for master) CoinZeroN(rowBlock,numberRows+1); for (iRow=0;iRow=0) { // already marked if (iBlock<0) { iBlock = columnBlock[iColumn]; } else if (iBlock != columnBlock[iColumn]) { // join two blocks int jBlock = columnBlock[iColumn]; numberGoodBlocks--; // Increase count of iBlock rowBlock[iBlock] += rowBlock[jBlock]; rowBlock[jBlock]=0; // First column of block jBlock int jColumn = whichRow[jBlock]; while (jColumn>=0) { columnBlock[jColumn]=iBlock; iColumn = jColumn; jColumn = whichColumn[jColumn]; } whichColumn[iColumn] = whichRow[iBlock]; whichRow[iBlock] = whichRow[jBlock]; whichRow[jBlock]=-1; } } } int n=end-start; // If not in block - then start one if (iBlock<0) { // unless null row if (n) { iBlock = numberBlocks; numberBlocks++; numberGoodBlocks++; int jColumn = column[start]; columnBlock[jColumn]=iBlock; whichRow[iBlock]=jColumn; numberMarkedColumns += n; rowBlock[iBlock] = n; for (CoinBigIndex j=start+1;j=0) { nn++; assert (iBlock=0) { n++; jColumn = whichColumn[jColumn]; } assert (n==temp[i]); } delete [] temp; } #endif rowsDone++; if (iBlock>=0) maximumInBlock = CoinMax(maximumInBlock,rowBlock[iBlock]); if (rowsDone>=checkAfterRows) { assert (numberGoodBlocks>0); double averageSize = static_cast(numberMarkedColumns)/ static_cast(numberGoodBlocks); #ifndef OSL_WAY double notionalBlocks = static_cast(numberMarkedColumns)/ averageSize; if (maximumInBlock<3*averageSize&&numberGoodBlocks>2) { if(best*(numberRows-rowsDone) < notionalBlocks) { best = notionalBlocks/ static_cast (numberRows-rowsDone); bestRow = kRow; } } #else if (maximumInBlock*101) { double test = maximumInBlock + 0.0*averageSize; if(best*static_cast(rowsDone) > test) { best = test/static_cast (rowsDone); bestRow = kRow; bestRowsDone=rowsDone; } } #endif } } #ifndef OSL_WAY best2[iWay]=best; #else if (bestRowsDonebest2[1]) { // Bottom rows in master iRow1=row2[0]+1; iRow2=numberRows; } else { // Top rows in master iRow1=0; iRow2=numberRows-row2[1]; } nMaster = iRow2-iRow1; CoinFillN(rowBlock+iRow1,nMaster,-1); } else { // sorted // Bottom rows in master (in order) int iRow1=row2[2]+1; nMaster = numberRows-iRow1; for (int i=iRow1;inumberRows) { goodDW=false; printf("%d rows out of %d would be in master - no good\n", nMaster,numberRows); delete [] rowBlock; delete [] columnBlock; delete [] whichRow; delete [] whichColumn; delete [] stack; CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper, columnLower,columnUpper,objective); model.setObjectiveOffset(objectiveOffset); addBlock("row_master","column_master",model); return 0; } } else { for (iRow=0;iRowmaxBlocks) { int iBlock; for (iRow=0;iRow=0) rowBlock[iRow] = iBlock%maxBlocks; } for (iColumn=0;iColumn=0) columnBlock[iColumn] = iBlock%maxBlocks; } numberBlocks=maxBlocks; } } // make up problems // Create all sub problems // Space for creating double * obj = new double [numberColumns]; double * columnLo = new double [numberColumns]; double * columnUp = new double [numberColumns]; double * rowLo = new double [numberRows]; double * rowUp = new double [numberRows]; // Counts int * rowCount = reinterpret_cast(rowLo); CoinZeroN(rowCount,numberBlocks); for (int i=0;i=0) rowCount[iBlock]++; } // allocate empty rows for (int i=0;i(rowUp); CoinZeroN(columnCount,numberBlocks); for (int i=0;i=0) columnCount[iBlock]++; } int maximumSize=0; for (int i=0;i4*(2*numberRows+numberColumns)) { // No good printf("Doesn't look good\n"); delete [] rowBlock; delete [] columnBlock; delete [] whichRow; delete [] whichColumn; delete [] obj ; delete [] columnLo ; delete [] columnUp ; delete [] rowLo ; delete [] rowUp ; CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper, columnLower,columnUpper,objective); model.setObjectiveOffset(objectiveOffset); addBlock("row_master","column_master",model); return 0; } // Name for master so at top addRowBlock(numberMasterRows,"row_master"); // Arrays // get full matrix CoinPackedMatrix fullMatrix = matrix; int numberRow2,numberColumn2; int iBlock; for (iBlock=0;iBlocksetOriginalIndices(whichRow,whichColumn); addBlock(rowName,columnName,block); // takes ownership // and top block numberRow2=0; // get top matrix for (iRow=0;iRowsetOriginalIndices(whichRow,whichColumn); addBlock("row_master",columnName,block); // takes ownership } // and master numberRow2=0; numberColumn2=0; for (iRow=0;iRowsetOriginalIndices(whichRow,whichColumn); addBlock("row_master","column_master",block); // takes ownership delete [] whichRow; delete [] whichColumn; delete [] obj ; delete [] columnLo ; delete [] columnUp ; delete [] rowLo ; delete [] rowUp ; } else if (type==2) { // Try master at beginning and end bool goodBenders=true; // get row copy CoinPackedMatrix rowCopy = matrix; rowCopy.reverseOrdering(); const int * row = matrix.getIndices(); const int * columnLength = matrix.getVectorLengths(); const CoinBigIndex * columnStart = matrix.getVectorStarts(); //const double * elementByColumn = matrix.getElements(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); //const double * elementByRow = rowCopy.getElements(); int numberColumns = matrix.getNumCols(); int * columnBlock = new int[numberColumns+1]; int iColumn; // Column counts (maybe look at long columns for master) CoinZeroN(columnBlock,numberColumns+1); for (iColumn=0;iColumn=0) { // already marked if (iBlock<0) { iBlock = rowBlock[iRow]; } else if (iBlock != rowBlock[iRow]) { // join two blocks int jBlock = rowBlock[iRow]; numberGoodBlocks--; // Increase count of iBlock columnBlock[iBlock] += columnBlock[jBlock]; columnBlock[jBlock]=0; // First row of block jBlock int jRow = whichColumn[jBlock]; while (jRow>=0) { rowBlock[jRow]=iBlock; iRow = jRow; jRow = whichRow[jRow]; } whichRow[iRow] = whichColumn[iBlock]; whichColumn[iBlock] = whichColumn[jBlock]; whichColumn[jBlock]=-1; } } } int n=end-start; // If not in block - then start one if (iBlock<0) { // unless null column if (n) { iBlock = numberBlocks; numberBlocks++; numberGoodBlocks++; int jRow = row[start]; rowBlock[jRow]=iBlock; whichColumn[iBlock]=jRow; numberMarkedRows += n; columnBlock[iBlock] = n; for (CoinBigIndex j=start+1;j=0) maximumInBlock = CoinMax(maximumInBlock,columnBlock[iBlock]); if (columnsDone>=checkAfterColumns) { assert (numberGoodBlocks>0); double averageSize = static_cast(numberMarkedRows)/ static_cast(numberGoodBlocks); #ifndef OSL_WAY double notionalBlocks = static_cast(numberMarkedRows)/ averageSize; if (maximumInBlock<3*averageSize&&numberGoodBlocks>2) { if(best*(numberColumns-columnsDone) < notionalBlocks) { best = notionalBlocks/ static_cast (numberColumns-columnsDone); bestColumn = kColumn; } } #else if (maximumInBlock*101) { double test = maximumInBlock + 0.0*averageSize; if(best*static_cast(columnsDone) > test) { best = test/static_cast (columnsDone); bestColumn = kColumn; bestColumnsDone=columnsDone; } } #endif } } #ifndef OSL_WAY best2[iWay]=best; #else if (bestColumnsDonebest2[1]) { // End columns in master iColumn1=column2[0]+1; iColumn2=numberColumns; } else { // Beginning columns in master iColumn1=0; iColumn2=numberColumns-column2[1]; } nMaster = iColumn2-iColumn1; CoinFillN(columnBlock+iColumn1,nMaster,-1); } else { // sorted // End columns in master (in order) int iColumn1=column2[2]+1; nMaster = numberColumns-iColumn1; for (int i=iColumn1;inumberColumns) { goodBenders=false; printf("%d columns out of %d would be in master - no good\n", nMaster,numberColumns); delete [] rowBlock; delete [] columnBlock; delete [] whichRow; delete [] whichColumn; delete [] stack; CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper, columnLower,columnUpper,objective); model.setObjectiveOffset(objectiveOffset); addBlock("row_master","column_master",model); return 0; } } else { for (iColumn=0;iColumnmaxBlocks) { int iBlock; for (iColumn=0;iColumn=0) columnBlock[iColumn] = iBlock%maxBlocks; } for (iRow=0;iRow=0) rowBlock[iRow] = iBlock%maxBlocks; } numberBlocks=maxBlocks; } } // make up problems // Create all sub problems // Space for creating double * obj = new double [numberColumns]; double * rowLo = new double [numberRows]; double * rowUp = new double [numberRows]; double * columnLo = new double [numberColumns]; double * columnUp = new double [numberColumns]; // Counts int * columnCount = reinterpret_cast(columnLo); CoinZeroN(columnCount,numberBlocks); for (int i=0;i=0) columnCount[iBlock]++; } // allocate empty columns for (int i=0;i(columnUp); CoinZeroN(rowCount,numberBlocks); for (int i=0;i=0) rowCount[iBlock]++; } int maximumSize=0; for (int i=0;i4*(2*numberColumns+numberRows)) { // No good printf("Doesn't look good\n"); delete [] rowBlock; delete [] columnBlock; delete [] whichRow; delete [] whichColumn; delete [] obj ; delete [] columnLo ; delete [] columnUp ; delete [] rowLo ; delete [] rowUp ; CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper, columnLower,columnUpper,objective); model.setObjectiveOffset(objectiveOffset); addBlock("row_master","column_master",model); return 0; } // Name for master so at beginning addColumnBlock(numberMasterColumns,"column_master"); // Arrays // get full matrix CoinPackedMatrix fullMatrix = matrix; int numberRow2,numberColumn2; int iBlock; for (iBlock=0;iBlocksetOriginalIndices(whichRow,whichColumn); addBlock(rowName,columnName,block); // takes ownership // and beginning block numberColumn2=0; // get beginning matrix for (iColumn=0;iColumnsetOriginalIndices(whichRow,whichColumn); addBlock(rowName,"column_master",block); // takes ownership } // and master numberRow2=0; numberColumn2=0; for (iColumn=0;iColumnsetOriginalIndices(whichRow,whichColumn); addBlock("row_master","column_master",block); // takes ownership delete [] whichRow; delete [] whichColumn; delete [] obj ; delete [] columnLo ; delete [] columnUp ; delete [] rowLo ; delete [] rowUp ; } else { abort(); } return numberBlocks; } /* Decompose a CoinModel 1 - try D-W 2 - try Benders 3 - try Staircase Returns number of blocks or zero if no structure */ int CoinStructuredModel::decompose(const CoinModel & coinModel, int type, int maxBlocks) { const CoinPackedMatrix * matrix = coinModel.packedMatrix(); assert (matrix!=NULL); // Arrays const double * objective = coinModel.objectiveArray(); const double * columnLower = coinModel.columnLowerArray(); const double * columnUpper = coinModel.columnUpperArray(); const double * rowLower = coinModel.rowLowerArray(); const double * rowUpper = coinModel.rowUpperArray(); return decompose(*matrix, rowLower, rowUpper, columnLower, columnUpper, objective, type,maxBlocks, coinModel.objectiveOffset()); } // Return block corresponding to row and column const CoinBaseModel * CoinStructuredModel::block(int row,int column) const { const CoinBaseModel * block = NULL; if (blockType_) { for (int iBlock=0;iBlock(blocks_[iBlock]); assert (block); break; } } } return block; } /* Fill pointers corresponding to row and column. False if any missing */ CoinModelBlockInfo CoinStructuredModel::block(int row,int column, const double * & rowLower, const double * & rowUpper, const double * & columnLower, const double * & columnUpper, const double * & objective) const { CoinModelBlockInfo info; //memset(&info,0,sizeof(info)); rowLower=NULL; rowUpper=NULL; columnLower=NULL; columnUpper=NULL; objective=NULL; if (blockType_) { for (int iBlock=0;iBlockrowLowerArray(); rowUpper = thisBlock->rowUpperArray(); } } if (blockType_[iBlock].columnBlock==column) { if (blockType_[iBlock].bounds) { info.bounds=1; columnLower = thisBlock->columnLowerArray(); columnUpper = thisBlock->columnUpperArray(); objective = thisBlock->objectiveArray(); } } } } return info; } // Return block number corresponding to row and column int CoinStructuredModel::blockIndex(int row,int column) const { int block=-1; if (blockType_) { for (int iBlock=0;iBlock