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

ClpFactorization.cpp

00001 // Copyright (C) 2002, International Business Machines
00002 // Corporation and others.  All Rights Reserved.
00003 
00004 #include "CoinPragma.hpp"
00005 #include "ClpFactorization.hpp"
00006 #include "ClpQuadraticObjective.hpp"
00007 #include "CoinHelperFunctions.hpp"
00008 #include "CoinIndexedVector.hpp"
00009 #include "ClpSimplex.hpp"
00010 #include "ClpMatrixBase.hpp"
00011 #include "ClpNetworkBasis.hpp"
00012 #include "ClpNetworkMatrix.hpp"
00013 //#define CHECK_NETWORK
00014 #ifdef CHECK_NETWORK
00015 const static bool doCheck=true;
00016 #else
00017 const static bool doCheck=false;
00018 #endif
00019 
00020 //#############################################################################
00021 // Constructors / Destructor / Assignment
00022 //#############################################################################
00023 
00024 //-------------------------------------------------------------------
00025 // Default Constructor 
00026 //-------------------------------------------------------------------
00027 ClpFactorization::ClpFactorization () :
00028    CoinFactorization() 
00029 {
00030   networkBasis_ = NULL;
00031 }
00032 
00033 //-------------------------------------------------------------------
00034 // Copy constructor 
00035 //-------------------------------------------------------------------
00036 ClpFactorization::ClpFactorization (const ClpFactorization & rhs) :
00037    CoinFactorization(rhs) 
00038 {
00039   if (rhs.networkBasis_)
00040     networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
00041   else
00042     networkBasis_=NULL;
00043 }
00044 
00045 ClpFactorization::ClpFactorization (const CoinFactorization & rhs) :
00046    CoinFactorization(rhs) 
00047 {
00048   networkBasis_=NULL;
00049 }
00050 
00051 //-------------------------------------------------------------------
00052 // Destructor 
00053 //-------------------------------------------------------------------
00054 ClpFactorization::~ClpFactorization () 
00055 {
00056   delete networkBasis_;
00057 }
00058 
00059 //----------------------------------------------------------------
00060 // Assignment operator 
00061 //-------------------------------------------------------------------
00062 ClpFactorization &
00063 ClpFactorization::operator=(const ClpFactorization& rhs)
00064 {
00065   if (this != &rhs) {
00066     CoinFactorization::operator=(rhs);
00067     delete networkBasis_;
00068     if (rhs.networkBasis_)
00069       networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
00070     else
00071       networkBasis_=NULL;
00072   }
00073   return *this;
00074 }
00075 int 
00076 ClpFactorization::factorize ( ClpSimplex * model,
00077                               int solveType, bool valuesPass)
00078 {
00079   const ClpMatrixBase * matrix = model->clpMatrix(); 
00080   int numberRows = model->numberRows();
00081   int numberColumns = model->numberColumns();
00082   // If too many compressions increase area
00083   if (numberPivots_>1&&numberCompressions_*10 > numberPivots_+10) {
00084     areaFactor_ *= 1.1;
00085   }
00086   if (!networkBasis_||doCheck) {
00087     status_=-99;
00088     int * pivotVariable = model->pivotVariable();
00089     //returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
00090     while (status_<-98) {
00091       
00092       int i;
00093       int numberBasic=0;
00094       int numberRowBasic;
00095       for (i=0;i<numberRows;i++) {
00096         if (model->getRowStatus(i) == ClpSimplex::basic) 
00097           pivotVariable[numberBasic++]=i;
00098       }
00099       numberRowBasic=numberBasic;
00100       for (i=0;i<numberColumns;i++) {
00101         if (model->getColumnStatus(i) == ClpSimplex::basic) 
00102           pivotVariable[numberBasic++]=i;
00103       }
00104       assert (numberBasic<=numberRows);
00105       // see if matrix a network
00106       ClpNetworkMatrix* networkMatrix =
00107         dynamic_cast< ClpNetworkMatrix*>(model->clpMatrix());
00108       // If network - still allow ordinary factorization first time for laziness
00109       int saveMaximumPivots = maximumPivots();
00110       delete networkBasis_;
00111       networkBasis_ = NULL;
00112       if (networkMatrix&&!doCheck)
00113         maximumPivots(1);
00114       while (status_==-99) {
00115         // maybe for speed will be better to leave as many regions as possible
00116         gutsOfDestructor();
00117         gutsOfInitialize(2);
00118         CoinBigIndex numberElements=numberRowBasic;
00119 
00120         // compute how much in basis
00121 
00122         int i;
00123 
00124         numberElements +=matrix->fillBasis(model,
00125                                            pivotVariable+numberRowBasic, 
00126                                            numberRowBasic,
00127                                            numberBasic-numberRowBasic,
00128                                            NULL,NULL,NULL);
00129 
00130         numberElements = 3 * numberBasic + 3 * numberElements + 10000;
00131         getAreas ( numberRows, numberBasic, numberElements,
00132                    2 * numberElements );
00133         //fill
00134         //copy
00135         numberElements=numberRowBasic;
00136         for (i=0;i<numberRowBasic;i++) {
00137           int iRow = pivotVariable[i];
00138           indexRowU_[i]=iRow;
00139           indexColumnU_[i]=i;
00140           elementU_[i]=slackValue_;
00141         }
00142         numberElements +=matrix->fillBasis(model, 
00143                                            pivotVariable+numberRowBasic, 
00144                                            numberRowBasic, 
00145                                            numberBasic-numberRowBasic,
00146                                            indexRowU_+numberElements, 
00147                                            indexColumnU_+numberElements,
00148                                            elementU_+numberElements);
00149         lengthU_ = numberElements;
00150 
00151         preProcess ( 0 );
00152         factor (  );
00153         if (status_==-99) {
00154           // get more memory
00155           areaFactor(2.0*areaFactor());
00156         }
00157       }
00158       // If we get here status is 0 or -1
00159       if (status_ == 0) {
00160         int * permuteBack = permuteBack_;
00161         int * back = pivotColumnBack_;
00162         int * pivotTemp = pivotColumn_;
00163         ClpDisjointCopyN ( pivotVariable, numberRows_ , pivotTemp  );
00164         // Redo pivot order
00165         for (i=0;i<numberRowBasic;i++) {
00166           int k = pivotTemp[i];
00167           // so rowIsBasic[k] would be permuteBack[back[i]]
00168           pivotVariable[permuteBack[back[i]]]=k+numberColumns;
00169         }
00170         for (;i<numberRows;i++) {
00171           int k = pivotTemp[i];
00172           // so rowIsBasic[k] would be permuteBack[back[i]]
00173           pivotVariable[permuteBack[back[i]]]=k;
00174         }
00175         // Set up permutation vector
00176         // these arrays start off as copies of permute
00177         // (and we could use permute_ instead of pivotColumn (not back though))
00178         ClpDisjointCopyN ( permute_, numberRows_ , pivotColumn_  );
00179         ClpDisjointCopyN ( permuteBack_, numberRows_ , pivotColumnBack_  );
00180         if (networkMatrix) {
00181           maximumPivots(saveMaximumPivots);
00182           // create network factorization
00183           if (doCheck)
00184             delete networkBasis_; // temp
00185           networkBasis_ = new ClpNetworkBasis(model,numberRows_,
00186                                               pivotRegion_,
00187                                               permuteBack_,
00188                                               startColumnU_,
00189                                               numberInColumn_,
00190                                               indexRowU_,
00191                                               elementU_);
00192           // kill off arrays in ordinary factorization
00193           if (!doCheck) {
00194             gutsOfDestructor();
00195 #if 0
00196             // but put back permute arrays so odd things will work
00197             int numberRows = model->numberRows();
00198             pivotColumnBack_ = new int [numberRows];
00199             permute_ = new int [numberRows];
00200             int i;
00201             for (i=0;i<numberRows;i++) {
00202               pivotColumnBack_[i]=i;
00203               permute_[i]=i;
00204             }
00205 #endif
00206           }
00207         } else {
00208           // See if worth going sparse and when
00209           if (numberFtranCounts_>100) {
00210             ftranAverageAfterL_ = max(ftranCountAfterL_/ftranCountInput_,1.0);
00211             ftranAverageAfterR_ = max(ftranCountAfterR_/ftranCountAfterL_,1.0);
00212             ftranAverageAfterU_ = max(ftranCountAfterU_/ftranCountAfterR_,1.0);
00213             assert (ftranCountInput_&&ftranCountAfterL_&&ftranCountAfterR_);
00214             if (btranCountInput_&&btranCountAfterU_&&btranCountAfterR_) {
00215               btranAverageAfterU_ = max(btranCountAfterU_/btranCountInput_,1.0);
00216               btranAverageAfterR_ = max(btranCountAfterR_/btranCountAfterU_,1.0);
00217               btranAverageAfterL_ = max(btranCountAfterL_/btranCountAfterR_,1.0);
00218             } else {
00219               // we have not done any useful btrans (values pass?)
00220               btranAverageAfterU_ = 1.0;
00221               btranAverageAfterR_ = 1.0;
00222               btranAverageAfterL_ = 1.0;
00223             }
00224           }
00225           // scale back
00226           
00227           ftranCountInput_ *= 0.8;
00228           ftranCountAfterL_ *= 0.8;
00229           ftranCountAfterR_ *= 0.8;
00230           ftranCountAfterU_ *= 0.8;
00231           btranCountInput_ *= 0.8;
00232           btranCountAfterU_ *= 0.8;
00233           btranCountAfterR_ *= 0.8;
00234           btranCountAfterL_ *= 0.8;
00235         }
00236       } else if (status_ == -1&&(solveType==0||solveType==2)) {
00237         // This needs redoing as it was merged coding - does not need array
00238         int numberTotal = numberRows+numberColumns;
00239         int * isBasic = new int [numberTotal];
00240         int * rowIsBasic = isBasic+numberColumns;
00241         int * columnIsBasic = isBasic;
00242         for (i=0;i<numberTotal;i++) 
00243           isBasic[i]=-1;
00244         for (i=0;i<numberRowBasic;i++) {
00245           int iRow = pivotVariable[i];
00246           rowIsBasic[iRow]=1;
00247         }
00248         for (;i<numberBasic;i++) {
00249           int iColumn = pivotVariable[i];
00250           columnIsBasic[iColumn]=1;
00251         }
00252         numberBasic=0;
00253         for (i=0;i<numberRows;i++) 
00254           pivotVariable[i]=-1;
00255         // mark as basic or non basic
00256         for (i=0;i<numberRows;i++) {
00257           if (rowIsBasic[i]>=0) {
00258             if (pivotColumn_[numberBasic]>=0) 
00259               rowIsBasic[i]=pivotColumn_[numberBasic];
00260             else
00261               rowIsBasic[i]=-1;
00262             numberBasic++;
00263           }
00264         }
00265         for (i=0;i<numberColumns;i++) {
00266           if (columnIsBasic[i]>=0) {
00267             if (pivotColumn_[numberBasic]>=0) 
00268               columnIsBasic[i]=pivotColumn_[numberBasic];
00269             else
00270               columnIsBasic[i]=-1;
00271             numberBasic++;
00272           }
00273         }
00274         // leave pivotVariable in useful form for cleaning basis
00275         int * pivotVariable = model->pivotVariable();
00276         for (i=0;i<numberRows;i++) {
00277           pivotVariable[i]=-1;
00278         }
00279         for (i=0;i<numberRows;i++) {
00280           if (model->getRowStatus(i) == ClpSimplex::basic) {
00281             int iPivot = rowIsBasic[i];
00282             if (iPivot>=0) 
00283               pivotVariable[iPivot]=i+numberColumns;
00284           }
00285         }
00286         for (i=0;i<numberColumns;i++) {
00287           if (model->getColumnStatus(i) == ClpSimplex::basic) {
00288             int iPivot = columnIsBasic[i];
00289             if (iPivot>=0) 
00290               pivotVariable[iPivot]=i;
00291           }
00292         }
00293         delete [] isBasic;
00294         double * columnLower = model->lowerRegion();
00295         double * columnUpper = model->upperRegion();
00296         double * columnActivity = model->solutionRegion();
00297         double * rowLower = model->lowerRegion(0);
00298         double * rowUpper = model->upperRegion(0);
00299         double * rowActivity = model->solutionRegion(0);
00300         //redo basis - first take ALL columns out
00301         int iColumn;
00302         double largeValue = model->largeValue();
00303         for (iColumn=0;iColumn<numberColumns;iColumn++) {
00304           if (model->getColumnStatus(iColumn)==ClpSimplex::basic) {
00305             // take out
00306             if (!valuesPass) {
00307               double lower=columnLower[iColumn];
00308               double upper=columnUpper[iColumn];
00309               double value=columnActivity[iColumn];
00310               if (lower>-largeValue||upper<largeValue) {
00311                 if (fabs(value-lower)<fabs(value-upper)) {
00312                   model->setColumnStatus(iColumn,ClpSimplex::atLowerBound);
00313                   columnActivity[iColumn]=lower;
00314                 } else {
00315                   model->setColumnStatus(iColumn,ClpSimplex::atUpperBound);
00316                   columnActivity[iColumn]=upper;
00317                 }
00318               } else {
00319                 model->setColumnStatus(iColumn,ClpSimplex::isFree);
00320               }
00321             } else {
00322               model->setColumnStatus(iColumn,ClpSimplex::superBasic);
00323             }
00324           }
00325         }
00326         int iRow;
00327         for (iRow=0;iRow<numberRows;iRow++) {
00328           int iSequence=pivotVariable[iRow];
00329           if (iSequence>=0) {
00330             // basic
00331             if (iSequence>=numberColumns) {
00332               // slack in - leave
00333               //assert (iSequence-numberColumns==iRow);
00334             } else {
00335               // put back structural
00336               model->setColumnStatus(iSequence,ClpSimplex::basic);
00337             }
00338           } else {
00339             // put in slack
00340             model->setRowStatus(iRow,ClpSimplex::basic);
00341           }
00342         }
00343         // signal repeat
00344         status_=-99;
00345         // set fixed if they are
00346         for (iRow=0;iRow<numberRows;iRow++) {
00347           if (model->getRowStatus(iRow)!=ClpSimplex::basic ) {
00348             if (rowLower[iRow]==rowUpper[iRow]) {
00349               rowActivity[iRow]=rowLower[iRow];
00350               model->setRowStatus(iRow,ClpSimplex::isFixed);
00351             }
00352           }
00353         }
00354         for (iColumn=0;iColumn<numberColumns;iColumn++) {
00355           if (model->getColumnStatus(iColumn)!=ClpSimplex::basic ) {
00356             if (columnLower[iColumn]==columnUpper[iColumn]) {
00357               columnActivity[iColumn]=columnLower[iColumn];
00358               model->setColumnStatus(iColumn,ClpSimplex::isFixed);
00359             }
00360           }
00361         }
00362       } 
00363     }
00364   } else {
00365     // network - fake factorization - do nothing
00366     status_=0;
00367   }
00368 
00369   if (!status_) {
00370     // take out part if quadratic
00371     if (model->algorithm()==2) {
00372       ClpObjective * obj = model->objectiveAsObject();
00373       ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(obj));
00374       assert (quadraticObj);
00375       CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
00376       int numberXColumns = quadratic->getNumCols();
00377       assert (numberXColumns<numberColumns);
00378       int base = numberColumns-numberXColumns;
00379       int * which = new int [numberXColumns];
00380       int * pivotVariable = model->pivotVariable();
00381       int * permute = pivotColumn();
00382       int i;
00383       int n=0;
00384       for (i=0;i<numberRows;i++) {
00385         int iSj = pivotVariable[i]-base;
00386         if (iSj>=0&&iSj<numberXColumns) 
00387           which[n++]=permute[i];
00388       }
00389       if (n)
00390         emptyRows(n,which);
00391       delete [] which;
00392     }
00393   }
00394   return status_;
00395 }
00396 /* Replaces one Column to basis,
00397    returns 0=OK, 1=Probably OK, 2=singular, 3=no room
00398    If checkBeforeModifying is true will do all accuracy checks
00399    before modifying factorization.  Whether to set this depends on
00400    speed considerations.  You could just do this on first iteration
00401    after factorization and thereafter re-factorize
00402    partial update already in U */
00403 int 
00404 ClpFactorization::replaceColumn ( CoinIndexedVector * regionSparse,
00405                       int pivotRow,
00406                       double pivotCheck ,
00407                       bool checkBeforeModifying)
00408 {
00409   if (!networkBasis_) {
00410     return CoinFactorization::replaceColumn(regionSparse,
00411                                             pivotRow,
00412                                             pivotCheck,
00413                                             checkBeforeModifying);
00414   } else {
00415     if (doCheck) {
00416       int returnCode = CoinFactorization::replaceColumn(regionSparse,
00417                                                         pivotRow,
00418                                                         pivotCheck,
00419                                                         checkBeforeModifying);
00420       networkBasis_->replaceColumn(regionSparse,
00421                                    pivotRow);
00422       return returnCode;
00423     } else {
00424       // increase number of pivots
00425       numberPivots_++;
00426       return networkBasis_->replaceColumn(regionSparse,
00427                                    pivotRow);
00428     }
00429   }
00430 }
00431 
00432 /* Updates one column (FTRAN) from region2
00433    number returned is negative if no room
00434    region1 starts as zero and is zero at end */
00435 int 
00436 ClpFactorization::updateColumnFT ( CoinIndexedVector * regionSparse,
00437                                    CoinIndexedVector * regionSparse2)
00438 {
00439 #ifdef CLP_DEBUG
00440   regionSparse->checkClear();
00441 #endif
00442   if (!networkBasis_) {
00443     collectStatistics_ = true;
00444     int returnValue= CoinFactorization::updateColumnFT(regionSparse,
00445                                                        regionSparse2);
00446     collectStatistics_ = false;
00447     return returnValue;
00448   } else {
00449 #ifdef CHECK_NETWORK
00450     CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
00451     int returnCode = CoinFactorization::updateColumnFT(regionSparse,
00452                                                        regionSparse2);
00453     networkBasis_->updateColumn(regionSparse,save);
00454     int i;
00455     double * array = regionSparse2->denseVector();
00456     double * array2 = save->denseVector();
00457     for (i=0;i<numberRows_;i++) {
00458       double value1 = array[i];
00459       double value2 = array2[i];
00460       assert (value1==value2);
00461     }
00462     delete save;
00463     return returnCode;
00464 #else
00465     networkBasis_->updateColumn(regionSparse,regionSparse2,-1);
00466     return 1;
00467 #endif
00468   }
00469 }
00470 /* Updates one column (FTRAN) from region2
00471    number returned is negative if no room
00472    region1 starts as zero and is zero at end */
00473 int 
00474 ClpFactorization::updateColumn ( CoinIndexedVector * regionSparse,
00475                                  CoinIndexedVector * regionSparse2,
00476                                  bool noPermute) const
00477 {
00478 #ifdef CLP_DEBUG
00479   if (!noPermute)
00480     regionSparse->checkClear();
00481 #endif
00482   if (!networkBasis_) {
00483     collectStatistics_ = true;
00484     int returnValue= CoinFactorization::updateColumn(regionSparse,
00485                                                      regionSparse2,
00486                                                      noPermute);
00487     collectStatistics_ = false;
00488     return returnValue;
00489   } else {
00490 #ifdef CHECK_NETWORK
00491     CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
00492     int returnCode = CoinFactorization::updateColumn(regionSparse,
00493                                                      regionSparse2,
00494                                                      noPermute);
00495     networkBasis_->updateColumn(regionSparse,save);
00496     int i;
00497     double * array = regionSparse2->denseVector();
00498     double * array2 = save->denseVector();
00499     for (i=0;i<numberRows_;i++) {
00500       double value1 = array[i];
00501       double value2 = array2[i];
00502       assert (value1==value2);
00503     }
00504     delete save;
00505     return returnCode;
00506 #else
00507     networkBasis_->updateColumn(regionSparse,regionSparse2,-1);
00508     return 1;
00509 #endif
00510   }
00511 }
00512 /* Updates one column (BTRAN) from region2
00513    region1 starts as zero and is zero at end */
00514 int 
00515 ClpFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
00516                           CoinIndexedVector * regionSparse2) const
00517 {
00518   if (!networkBasis_) {
00519     collectStatistics_ = true;
00520     return CoinFactorization::updateColumnTranspose(regionSparse,
00521                                                     regionSparse2);
00522     collectStatistics_ = false;
00523   } else {
00524 #ifdef CHECK_NETWORK
00525       CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
00526       int returnCode = CoinFactorization::updateColumnTranspose(regionSparse,
00527                                                                 regionSparse2);
00528       networkBasis_->updateColumnTranspose(regionSparse,save);
00529       int i;
00530       double * array = regionSparse2->denseVector();
00531       double * array2 = save->denseVector();
00532       for (i=0;i<numberRows_;i++) {
00533         double value1 = array[i];
00534         double value2 = array2[i];
00535         assert (value1==value2);
00536       }
00537       delete save;
00538       return returnCode;
00539 #else
00540       return networkBasis_->updateColumnTranspose(regionSparse,regionSparse2);
00541 #endif
00542   }
00543 }
00544 /* makes a row copy of L for speed and to allow very sparse problems */
00545 void 
00546 ClpFactorization::goSparse()
00547 {
00548   if (!networkBasis_) 
00549     CoinFactorization::goSparse();
00550 }
00551 // Cleans up i.e. gets rid of network basis 
00552 void 
00553 ClpFactorization::cleanUp()
00554 {
00555   delete networkBasis_;
00556   networkBasis_=NULL;
00557   resetStatistics();
00558 }
00560 bool 
00561 ClpFactorization::needToReorder() const
00562 {
00563 #ifdef CHECK_NETWORK
00564   return true;
00565 #endif
00566   if (!networkBasis_)
00567     return true;
00568   else
00569     return false;
00570 }

Generated on Wed Dec 3 14:37:25 2003 for CLP by doxygen 1.3.5