Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

OsiDylpWarmStartBasis.cpp

00001 
00007 #ifdef COIN_USE_DYLP
00008 
00009 #ifdef _MSC_VER
00010 
00011 /* Turn off compiler warning about long names */
00012 
00013 #  pragma warning(disable:4786)
00014 
00015 #endif // _MSC_VER
00016 
00017 /* Cut name lengths for readability. */
00018 
00019 #define ODWSB OsiDylpWarmStartBasis
00020 #define CWSB CoinWarmStartBasis
00021 
00041 namespace {
00042   char sccsid[] = "%W%  %G%" ;
00043   char cvsid[] = "$Id: OsiDylpWarmStartBasis.cpp,v 1.2 2003/10/23 17:32:22 lou-oss Exp $" ;
00044 }
00045 
00046 #include <vector>
00047 #include <cassert>
00048 #include <iostream>
00049 #include "OsiDylpWarmStartBasis.hpp"
00050 
00051 using std::vector ;
00052 
00053 /*
00054   A macro to standardize the size of the status arrays. CWSB::Status is the
00055   status enum, and currently it occupies 2 bits, packed 4 per char (note the
00056   implicit assumption that a char is 1 byte).  This macro calculates the
00057   number of bytes needed to hold ns status entires, rounded up to the nearest
00058   int.
00059 */
00060 
00061 #define STATPERBYTE 4
00062 #define STATALLOCUNIT sizeof(int)
00063 #define STATBYTES(zz_ns_zz) \
00064   (((zz_ns_zz+STATALLOCUNIT*STATPERBYTE-1)/(STATALLOCUNIT*STATPERBYTE))* \
00065    STATALLOCUNIT)
00066   
00067 
00076 
00079 ODWSB::OsiDylpWarmStartBasis ()
00080 
00081   : CWSB(),
00082     phase_(dyINV),
00083     constraintStatus_(0)
00084 
00085 { /* intentionally left blank */ }
00086 
00087 
00092 ODWSB::OsiDylpWarmStartBasis (const OsiDylpWarmStartBasis &ws)
00093 
00094   : CWSB(ws),
00095     phase_(ws.phase_),
00096     constraintStatus_(0)
00097 
00098 { int constatsze = STATBYTES(getNumArtificial()) ;
00099   constraintStatus_ = new char[constatsze] ;
00100   memcpy(constraintStatus_,ws.constraintStatus_,constatsze) ; }
00101 
00102 
00108 CoinWarmStart *ODWSB::clone () const
00109 
00110 { const ODWSB *odwsb_orig = dynamic_cast<const ODWSB *>(this) ;
00111   ODWSB *odwsb_new = 0 ;
00112   if (odwsb_orig)
00113   { odwsb_new = new OsiDylpWarmStartBasis(*odwsb_orig) ; }
00114   return (dynamic_cast<CoinWarmStart *>(odwsb_new)) ; }
00115 
00125 ODWSB::OsiDylpWarmStartBasis
00126   (int ns, int na, const char *sStat, const char *aStat, const char *cStat)
00127 
00128   : CWSB(ns,na,sStat,aStat),
00129     phase_(dyPRIMAL1),
00130     constraintStatus_(0)
00131 
00132 { int constatsze = STATBYTES(na) ;
00133   constraintStatus_ = new char[constatsze] ;
00134 /*
00135   If a status array is given, copy it in. If there's no array provided, assume
00136   all constraints are active. Set up a byte with the correct pattern and use it
00137   to initialize the constraint status.
00138 */
00139   if (cStat)
00140   { memcpy(constraintStatus_,cStat,constatsze) ; }
00141   else
00142   { char byteActive = 0 ;
00143     int i ;
00144     for (i = 0 ; i <= 3 ; i++) setStatus(&byteActive,i,CWSB::atLowerBound) ;
00145     memset(constraintStatus_,byteActive,constatsze) ; } }
00146 
00151 OsiDylpWarmStartBasis& ODWSB::operator= (const OsiDylpWarmStartBasis &rhs)
00152 
00153 { if (this != &rhs)
00154   { CWSB::operator=(rhs) ;
00155     phase_ = rhs.phase_ ;
00156     delete[] constraintStatus_ ;
00157     int constatsze = STATBYTES(getNumArtificial()) ;
00158     constraintStatus_ = new char[constatsze] ;
00159     memcpy(constraintStatus_,rhs.constraintStatus_,constatsze) ; }
00160   
00161   return *this ; }
00162 
00163 
00182 void ODWSB::assignBasisStatus
00183   (int ns, int na, char *&sStat, char *&aStat, char *&cStat)
00184 
00185 { CWSB::assignBasisStatus(ns,na,sStat,aStat) ;
00186   phase_ = dyPRIMAL1 ;
00187   delete[] constraintStatus_ ;
00188   constraintStatus_ = cStat ;
00189   cStat = 0 ; }
00190 
00210 void ODWSB::assignBasisStatus (int ns, int na, char *&sStat, char *&aStat)
00211 
00212 { int constatsze = STATBYTES(na) ;
00213   char byteActive = 0 ;
00214   int i ;
00215 
00216   CWSB::assignBasisStatus(ns,na,sStat,aStat) ;
00217   phase_ = dyPRIMAL1 ;
00218 
00219   delete[] constraintStatus_ ;
00220   constraintStatus_ = new char[constatsze] ;
00221   for (i = 0 ; i <= 3 ; i++) setStatus(&byteActive,i,CWSB::atLowerBound) ;
00222   memset(constraintStatus_,byteActive,constatsze) ; }
00223 
00224 ODWSB::~OsiDylpWarmStartBasis () { delete[] constraintStatus_ ; }
00225 
00231 void ODWSB::setSize (int ns, int na)
00232 
00233 { CWSB::setSize(ns,na) ;
00234   phase_ = dyINV ;
00235   delete[] constraintStatus_ ;
00236   int constatsze = STATBYTES(na) ;
00237   constraintStatus_ = new char[constatsze] ;
00238   assert(((int) CWSB::isFree == 0)) ;
00239   memset(constraintStatus_,0,constatsze) ; }
00240 
00251 void ODWSB::resize (int numRows, int numCols)
00252 
00253 { int concnt = getNumArtificial() ;
00254   
00255   CWSB::resize(numRows,numCols) ;
00256 
00257   if (numRows != concnt)
00258   { int oldsze = STATBYTES(concnt) ;
00259     int newsze = STATBYTES(numRows) ;
00260     char *newStat = new char[newsze] ;
00261 /*
00262   If the new capacity is smaller, truncate the existing basis.
00263 */
00264     if (oldsze > newsze)
00265     { memcpy(newStat,constraintStatus_,newsze) ; }
00266 /*
00267   If the new capacity is larger, copy the existing basis, then mark the
00268   additional constraints as active. We need to be a bit careful here, because
00269   the allocated sizes are rounded out. The strategy is to (possibly) overlap
00270   one byte, correcting it after initialization.
00271 */
00272     else
00273     { char byteActive = 0 ;
00274       int i,actualBytes ;
00275       actualBytes = concnt/STATPERBYTE ;
00276       for (i = 0 ; i <= 3 ; i++) setStatus(&byteActive,i,CWSB::atLowerBound) ;
00277       memcpy(newStat,constraintStatus_,oldsze) ;
00278       memset(newStat+actualBytes,byteActive,newsze-actualBytes) ;
00279       for (i = 0 ; i < concnt%STATPERBYTE ; i++)
00280         setStatus(newStat+actualBytes,i,
00281                   getStatus(constraintStatus_+actualBytes,i)) ; }
00282 
00283     delete [] constraintStatus_ ;
00284     constraintStatus_ = newStat ; } }
00285 
00286 
00292 /*
00293   To elaborate on the above comment: When a tight constraint is removed, new
00294   extreme points are exposed. There's a reasonable likelihood they'll be
00295   desireable points (since the tight constraint was most likely tight because
00296   it was blocking movement in a desireable direction). In essence, we want to
00297   take the next primal pivot and see what comes tight. That's a fair bit of
00298   work, and on balance best left to the client to decide if it's appropriate,
00299   or if something else should be done.
00300 */
00301 
00302 void ODWSB::deleteRows (int number, const int *which)
00303 
00304 { int oldconcnt = getNumArtificial() ;
00305   int i,k ;
00306 
00307   CWSB::deleteRows(number,which) ;
00308 
00309   int delcnt = 0 ;
00310   vector<bool> deleted = vector<bool>(oldconcnt) ;
00311   for (k = 0 ; k < number ; k++)
00312   { i = which[k] ;
00313     if (i >= 0 && i < oldconcnt && !deleted[i])
00314     { delcnt++ ;
00315       deleted[i] = true ; } }
00316 
00317   int newsze = STATBYTES(oldconcnt-delcnt) ;
00318   char *newStat = new char[newsze] ;
00319 
00320   k = 0 ;
00321   for (i = 0 ; i < oldconcnt ; i++)
00322   { Status status = getConStatus(i);
00323     if (!deleted[i])
00324     { setStatus(newStat,k,status) ;
00325       k++ ; } }
00326   
00327   delete [] constraintStatus_ ;
00328   constraintStatus_ = newStat ; }
00329 
00330 /*
00331   The good news is that CWSB::deleteColumns works just fine for ODWSB.
00332 */
00333 
00335 
00341 
00347 int ODWSB::numberActiveConstraints () const
00348 
00349 { int i ;
00350   int concnt = getNumArtificial() ;
00351   int actcnt = 0 ;
00352 
00353   for (i = 0 ; i < concnt ; i++)
00354     if (getStatus(constraintStatus_,i) == CWSB::atLowerBound) actcnt++ ;
00355   
00356   return (actcnt) ; }
00357 
00363 
00373 CoinWarmStartDiff *ODWSB::generateDiff
00374   (const CoinWarmStart *const oldCWS) const
00375 {
00376 /*
00377   Make sure the parameter is an OsiDylpWarmStartBasis.
00378 */
00379   const OsiDylpWarmStartBasis *oldBasis =
00380       dynamic_cast<const OsiDylpWarmStartBasis *>(oldCWS) ;
00381   if (!oldBasis)
00382   { throw CoinError("Old basis not OsiDylpWarmStartBasis.",
00383                     "generateDiff","OsiDylpWarmStartBasis") ; }
00384   const OsiDylpWarmStartBasis *newBasis = this ;
00385 /*
00386   Make sure newBasis is equal or bigger than oldBasis. Calculate the worst case
00387   number of diffs and allocate vectors to hold them.
00388 */
00389   const int oldArtifCnt = oldBasis->getNumArtificial() ;
00390   const int newArtifCnt = newBasis->getNumArtificial() ;
00391 
00392   assert(newArtifCnt >= oldArtifCnt) ;
00393 /*
00394   Ok, we're good to go. Call CWSB::generateDiff to deal with the logical and
00395   structural arrays.
00396 */
00397   const CoinWarmStartBasisDiff *cwsbDiff =
00398     dynamic_cast<const CoinWarmStartBasisDiff *>(CWSB::generateDiff(oldCWS)) ;
00399 /*
00400   Now generate diffs for the constraint array.
00401 */
00402 
00403   int sizeOldArtif = (oldArtifCnt+15)>>4 ;
00404   int sizeNewArtif = (newArtifCnt+15)>>4 ;
00405   int maxBasisLength = sizeNewArtif ;
00406 
00407   unsigned int *diffNdx = new unsigned int [maxBasisLength]; 
00408   unsigned int *diffVal = new unsigned int [maxBasisLength]; 
00409 /*
00410   Scan the constraint status.
00411   For the portion of the status arrays which overlap, create
00412   diffs. Then add any additional status from newBasis.
00413 */
00414   const unsigned int *oldStatus =
00415       reinterpret_cast<const unsigned int *>(oldBasis->getConstraintStatus()) ;
00416   const unsigned int *newStatus = 
00417       reinterpret_cast<const unsigned int *>(newBasis->getConstraintStatus()) ;
00418   int numberChanged = 0 ;
00419   int i ;
00420   for (i = 0 ; i < sizeOldArtif ; i++)
00421   { if (oldStatus[i] != newStatus[i])
00422     { diffNdx[numberChanged] = i ;
00423       diffVal[numberChanged++] = newStatus[i] ; } }
00424   for ( ; i < sizeNewArtif ; i++)
00425   { diffNdx[numberChanged] = i ;
00426     diffVal[numberChanged++] = newStatus[i] ; }
00427 /*
00428   Create the object of our desire.
00429 */
00430   OsiDylpWarmStartBasisDiff *diff =
00431     new OsiDylpWarmStartBasisDiff(numberChanged,diffNdx,diffVal,cwsbDiff) ;
00432 /*
00433   Clean up and return.
00434 */
00435   delete[] diffNdx ;
00436   delete[] diffVal ;
00437 
00438   return (dynamic_cast<CoinWarmStartDiff *>(diff)) ; }
00439 
00448 void ODWSB::applyDiff (const CoinWarmStartDiff *const cwsdDiff)
00449 {
00450 /*
00451   Make sure we have an OsiDylpWarmStartBasisDiff
00452 */
00453   const OsiDylpWarmStartBasisDiff *diff =
00454     dynamic_cast<const OsiDylpWarmStartBasisDiff *>(cwsdDiff) ;
00455   if (!diff)
00456   { throw CoinError("Diff not OsiDylpWarmStartBasisDiff.",
00457                     "applyDiff","OsiDylpWarmStartBasis") ; }
00458 /*
00459   Call CWSB::applyDiff to deal with the logical and structural status.
00460 */
00461   CWSB::applyDiff(cwsdDiff) ;
00462 /*
00463   Now fix up the constraint status array. Application of the diff is by
00464   straighforward replacement of words in the status array.
00465 */
00466   const int numberChanges = diff->consze_ ;
00467   const unsigned int *diffNdxs = diff->condiffNdxs_ ;
00468   const unsigned int *diffVals = diff->condiffVals_ ;
00469   unsigned int *constraintStatus =
00470       reinterpret_cast<unsigned int *>(this->getConstraintStatus()) ;
00471 
00472   for (int i = 0 ; i < numberChanges ; i++)
00473   { unsigned int diffNdx = diffNdxs[i] ;
00474     unsigned int diffVal = diffVals[i] ;
00475     constraintStatus[diffNdx] = diffVal ; }
00476 
00477   return ; }
00478 
00480 
00481 
00487 
00493 void ODWSB::print () const
00494 
00495 { char conlett[] = {'I','?','?','A'} ;
00496   char statlett[] = {'F','B','U','L'} ;
00497   int i,basic_logicals,basic_structurals ;
00498 
00499   std::cout << "ODWSB: " ;
00500   std::cout << getNumArtificial() << " constraints (" <<
00501                numberActiveConstraints() << " active), " ;
00502   std::cout << getNumStructural() << " variables." << std::endl ;
00503 
00504   std::cout << "Rows: " ;
00505   for (i = 0 ; i < getNumArtificial() ; i++)
00506   { std::cout << conlett[getConStatus(i)] ; }
00507   std::cout << std::endl ;
00508 
00509   std::cout << "      " ;
00510   basic_logicals = 0 ;
00511   for (i = 0 ; i < getNumArtificial() ; i++)
00512   { std::cout << statlett[getArtifStatus(i)] ;
00513     if (getArtifStatus(i) == CWSB::basic) basic_logicals++ ; }
00514   std::cout << std::endl ;
00515   
00516   std::cout << "Cols: " ;
00517   basic_structurals = 0 ;
00518   for (i = 0 ; i < getNumStructural() ; i++)
00519   { std::cout << statlett[getStructStatus(i)] ;
00520     if (getStructStatus(i) == CWSB::basic) basic_structurals++ ; }
00521 
00522   std::cout << std::endl << "   basic: ("
00523             << basic_structurals << " + " << basic_logicals << ")" ;
00524   std::cout << std::endl ;
00525   
00526   return ; }
00527 
00529 
00530 
00531 
00532 
00533 /* Routines for OsiDylpWarmStartBasisDiff */
00534 
00535 /*
00536   Constructor given constraint diff data and a pointer to a
00537   CoinWarmStartBasisDiff object.
00538 */
00539 OsiDylpWarmStartBasisDiff::OsiDylpWarmStartBasisDiff (int sze,
00540   const unsigned int *const diffNdxs, const unsigned int *const diffVals,
00541   const CoinWarmStartBasisDiff *const cwsbd)
00542 
00543   : CoinWarmStartBasisDiff(*cwsbd),
00544     consze_(sze),
00545     condiffNdxs_(0),
00546     condiffVals_(0)
00547 
00548 { if (sze > 0)
00549   { condiffNdxs_ = new unsigned int[sze] ;
00550     memcpy(condiffNdxs_,diffNdxs,sze*sizeof(unsigned int)) ;
00551     condiffVals_ = new unsigned int[sze] ;
00552     memcpy(condiffVals_,diffVals,sze*sizeof(unsigned int)) ; }
00553   
00554   return ; }
00555 
00556 /*
00557   Copy constructor
00558 */
00559 OsiDylpWarmStartBasisDiff::OsiDylpWarmStartBasisDiff
00560   (const OsiDylpWarmStartBasisDiff &odwsbd)
00561   : CoinWarmStartBasisDiff(odwsbd),
00562     consze_(odwsbd.consze_),
00563     condiffNdxs_(0),
00564     condiffVals_(0)
00565 { if (odwsbd.consze_ > 0)
00566   { condiffNdxs_ = new unsigned int[odwsbd.consze_] ;
00567     memcpy(condiffNdxs_,odwsbd.condiffNdxs_,
00568            odwsbd.consze_*sizeof(unsigned int)) ;
00569     condiffVals_ = new unsigned int[odwsbd.consze_] ;
00570     memcpy(condiffVals_,odwsbd.condiffVals_,
00571            odwsbd.consze_*sizeof(unsigned int)) ; }
00572   
00573   return ; }
00574 
00575 /*
00576   Assignment --- for convenience when assigning objects containing
00577   CoinWarmStartBasisDiff objects.
00578 */
00579 OsiDylpWarmStartBasisDiff&
00580 OsiDylpWarmStartBasisDiff::operator= (const OsiDylpWarmStartBasisDiff &rhs)
00581 
00582 { if (this != &rhs)
00583   { CoinWarmStartBasisDiff::operator=(rhs) ;
00584     if (consze_ > 0)
00585     { delete[] condiffNdxs_ ;
00586       delete[] condiffVals_ ; }
00587     consze_ = rhs.consze_ ;
00588     if (consze_ > 0)
00589     { condiffNdxs_ = new unsigned int[consze_] ;
00590       memcpy(condiffNdxs_,rhs.condiffNdxs_,consze_*sizeof(unsigned int)) ;
00591       condiffVals_ = new unsigned int[consze_] ;
00592       memcpy(condiffVals_,rhs.condiffVals_,consze_*sizeof(unsigned int)) ; }
00593     else
00594     { condiffNdxs_ = 0 ;
00595       condiffVals_ = 0 ; } }
00596   
00597   return (*this) ; }
00598 
00599 
00600 #endif // COIN_USE_DYLP
00601 

Generated on Wed Dec 3 14:35:31 2003 for Osi by doxygen 1.3.5