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

OsiOslSolverInterfaceTest.cpp

00001 // Copyright (C) 2000, International Business Machines
00002 // Corporation and others.  All Rights Reserved.
00003 
00004 #if defined(_MSC_VER)
00005 // Turn off compiler warning about long names
00006 #  pragma warning(disable:4786)
00007 #endif
00008 
00009 #include <cassert>
00010 
00011 #include "OsiOslSolverInterface.hpp"
00012 #include "OsiCuts.hpp"
00013 #include "OsiRowCut.hpp"
00014 #include "OsiColCut.hpp"
00015 #include "CoinMessage.hpp"
00016 
00017 // below needed for pathetic branch and bound code
00018 #include <vector>
00019 #include <map>
00020 #ifndef _MSC_VER
00021   using std::max;
00022   using std::min;
00023 #endif
00024 // Trivial class for Branch and Bound
00025 
00026 class OsiNodeSimple  {
00027   
00028 public:
00029     
00030   // Default Constructor 
00031   OsiNodeSimple ();
00032 
00033   // Constructor from current state (and list of integers)
00034   // Also chooses branching variable (if none set to -1)
00035   OsiNodeSimple (OsiSolverInterface &model,
00036            int numberIntegers, int * integer);
00037   
00038   // Copy constructor 
00039   OsiNodeSimple ( const OsiNodeSimple &);
00040    
00041   // Assignment operator 
00042   OsiNodeSimple & operator=( const OsiNodeSimple& rhs);
00043 
00044   // Destructor 
00045   ~OsiNodeSimple ();
00046   
00047   // Public data
00048   // Basis (should use tree, but not as wasteful as bounds!)
00049   CoinWarmStartBasis basis_;
00050   // Objective value
00051   double objectiveValue_;
00052   // Branching variable (0 is first integer)
00053   int variable_;
00054   // Way to branch - -1 down (first), 1 up, -2 down (second), 2 up (second)
00055   int way_;
00056   // Number of integers (for length of arrays)
00057   int numberIntegers_;
00058   // Current value
00059   double value_;
00060   // Now I must use tree
00061   // Bounds stored in full (for integers)
00062   int * lower_;
00063   int * upper_;
00064 };
00065 
00066 
00067 OsiNodeSimple::OsiNodeSimple() :
00068   basis_(CoinWarmStartBasis()),
00069   objectiveValue_(1.0e100),
00070   variable_(-100),
00071   way_(-1),
00072   numberIntegers_(0),
00073   value_(0.5),
00074   lower_(NULL),
00075   upper_(NULL)
00076 {
00077 }
00078 OsiNodeSimple::OsiNodeSimple(OsiSolverInterface & model,
00079                  int numberIntegers, int * integer)
00080 {
00081   const CoinWarmStartBasis* ws =
00082     dynamic_cast<const CoinWarmStartBasis*>(model.getWarmStart());
00083 
00084   assert (ws!=NULL); // make sure not volume
00085   basis_ = CoinWarmStartBasis(*ws);
00086   variable_=-1;
00087   way_=-1;
00088   numberIntegers_=numberIntegers;
00089   value_=0.0;
00090   if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
00091     objectiveValue_ = model.getObjSense()*model.getObjValue();
00092   } else {
00093     objectiveValue_ = 1.0e100;
00094     lower_ = NULL;
00095     upper_ = NULL;
00096     return; // node cutoff
00097   }
00098   lower_ = new int [numberIntegers_];
00099   upper_ = new int [numberIntegers_];
00100   assert (upper_!=NULL);
00101   const double * lower = model.getColLower();
00102   const double * upper = model.getColUpper();
00103   const double * solution = model.getColSolution();
00104   int i;
00105   // Hard coded integer tolerance
00106 #define INTEGER_TOLERANCE 1.0e-6
00107   // Number of strong branching candidates
00108 #define STRONG_BRANCHING 5
00109 #ifdef STRONG_BRANCHING
00110   double upMovement[STRONG_BRANCHING];
00111   double downMovement[STRONG_BRANCHING];
00112   double solutionValue[STRONG_BRANCHING];
00113   int chosen[STRONG_BRANCHING];
00114   int iSmallest=0;
00115   // initialize distance from integer
00116   for (i=0;i<STRONG_BRANCHING;i++) {
00117     upMovement[i]=0.0;
00118     chosen[i]=-1;
00119   }
00120 #endif
00121   variable_=-1;
00122   // This has hard coded integer tolerance
00123   double mostAway=INTEGER_TOLERANCE;
00124   for (i=0;i<numberIntegers;i++) {
00125     int iColumn = integer[i];
00126     lower_[i]=(int)lower[iColumn];
00127     upper_[i]=(int)upper[iColumn];
00128     double value = solution[iColumn];
00129     value = max(value,(double) lower_[i]);
00130     value = min(value,(double) upper_[i]);
00131     double nearest = floor(value+0.5);
00132     if (fabs(value-nearest)>mostAway) {
00133 #ifdef STRONG_BRANCHING
00134       double away = fabs(value-nearest);
00135       if (away>upMovement[iSmallest]) {
00136         //add to list
00137         upMovement[iSmallest]=away;
00138         solutionValue[iSmallest]=value;
00139         chosen[iSmallest]=i;
00140         int j;
00141         iSmallest=-1;
00142         double smallest = 1.0;
00143         for (j=0;j<STRONG_BRANCHING;j++) {
00144           if (upMovement[j]<smallest) {
00145             smallest=upMovement[j];
00146             iSmallest=j;
00147           }
00148         }
00149       }
00150 #else
00151       mostAway=fabs(value-nearest);
00152       variable_=i;
00153       value_=value;
00154       if (value<=nearest)
00155         way_=1; // up
00156       else
00157         way_=-1; // down
00158 #endif
00159     }
00160   }
00161 #ifdef STRONG_BRANCHING
00162   int numberStrong=0;
00163   for (i=0;i<STRONG_BRANCHING;i++) {
00164     if (chosen[i]>=0) { 
00165       numberStrong ++;
00166       variable_ = chosen[i];
00167     }
00168   }
00169   if (numberStrong==1) {
00170     // just one - makes it easy
00171     int iColumn = integer[variable_];
00172     double value = solution[iColumn];
00173     value = max(value,(double) lower_[variable_]);
00174     value = min(value,(double) upper_[variable_]);
00175     double nearest = floor(value+0.5);
00176     value_=value;
00177     if (value<=nearest)
00178       way_=1; // up
00179     else
00180       way_=-1; // down
00181   } else if (numberStrong) {
00182     // more than one - choose
00183     bool chooseOne=true;
00184     model.markHotStart();
00185     for (i=0;i<STRONG_BRANCHING;i++) {
00186       int iInt = chosen[i];
00187       if (iInt>=0) {
00188         int iColumn = integer[iInt];
00189         double value = solutionValue[i]; // value of variable in original
00190         double objectiveChange;
00191         value = max(value,(double) lower_[iInt]);
00192         value = min(value,(double) upper_[iInt]);
00193 
00194         // try down
00195 
00196         model.setColUpper(iColumn,floor(value));
00197         model.solveFromHotStart();
00198         model.setColUpper(iColumn,upper_[iInt]);
00199         if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
00200           objectiveChange = model.getObjSense()*model.getObjValue()
00201             - objectiveValue_;
00202         } else {
00203           objectiveChange = 1.0e100;
00204         }
00205         downMovement[i]=objectiveChange;
00206 
00207         // try up
00208 
00209         model.setColLower(iColumn,ceil(value));
00210         model.solveFromHotStart();
00211         model.setColLower(iColumn,lower_[iInt]);
00212         if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
00213           objectiveChange = model.getObjSense()*model.getObjValue()
00214             - objectiveValue_;
00215         } else {
00216           objectiveChange = 1.0e100;
00217         }
00218         upMovement[i]=objectiveChange;
00219         
00220         /* Possibilities are:
00221            Both sides feasible - store
00222            Neither side feasible - set objective high and exit
00223            One side feasible - change bounds and resolve
00224         */
00225         bool solveAgain=false;
00226         if (upMovement[i]<1.0e100) {
00227           if(downMovement[i]<1.0e100) {
00228             // feasible - no action
00229           } else {
00230             // up feasible, down infeasible
00231             solveAgain = true;
00232             model.setColLower(iColumn,ceil(value));
00233           }
00234         } else {
00235           if(downMovement[i]<1.0e100) {
00236             // down feasible, up infeasible
00237             solveAgain = true;
00238             model.setColUpper(iColumn,floor(value));
00239           } else {
00240             // neither side feasible
00241             objectiveValue_=1.0e100;
00242             chooseOne=false;
00243             break;
00244           }
00245         }
00246         if (solveAgain) {
00247           // need to solve problem again - signal this
00248           variable_ = numberIntegers;
00249           chooseOne=false;
00250           break;
00251         }
00252       }
00253     }
00254     if (chooseOne) {
00255       // choose the one that makes most difference both ways
00256       double best = -1.0;
00257       double best2 = -1.0;
00258       for (i=0;i<STRONG_BRANCHING;i++) {
00259         int iInt = chosen[i];
00260         if (iInt>=0) {
00261           std::cout<<"Strong branching on "
00262                    <<i<<""<<iInt<<" down "<<downMovement[i]
00263                    <<" up "<<upMovement[i]
00264                    <<" value "<<solutionValue[i]
00265                    <<std::endl;
00266           bool better = false;
00267           if (min(upMovement[i],downMovement[i])>best) {
00268             // smaller is better
00269             better=true;
00270           } else if (min(upMovement[i],downMovement[i])>best-1.0e-5) {
00271             if (max(upMovement[i],downMovement[i])>best2+1.0e-5) {
00272               // smaller is about same, but larger is better
00273               better=true;
00274             }
00275           }
00276           if (better) {
00277             best = min(upMovement[i],downMovement[i]);
00278             best2 = max(upMovement[i],downMovement[i]);
00279             variable_ = iInt;
00280             double value = solutionValue[i];
00281             value = max(value,(double) lower_[variable_]);
00282             value = min(value,(double) upper_[variable_]);
00283             value_=value;
00284             if (upMovement[i]<=downMovement[i])
00285               way_=1; // up
00286             else
00287               way_=-1; // down
00288           }
00289         }
00290       }
00291     }
00292     // Delete the snapshot
00293     model.unmarkHotStart();
00294   }
00295 #endif
00296 }
00297 
00298 OsiNodeSimple::OsiNodeSimple(const OsiNodeSimple & rhs) 
00299 {  
00300   basis_=rhs.basis_;
00301   objectiveValue_=rhs.objectiveValue_;
00302   variable_=rhs.variable_;
00303   way_=rhs.way_;
00304   numberIntegers_=rhs.numberIntegers_;
00305   value_=rhs.value_;
00306   lower_=NULL;
00307   upper_=NULL;
00308   if (rhs.lower_!=NULL) {
00309     lower_ = new int [numberIntegers_];
00310     upper_ = new int [numberIntegers_];
00311     assert (upper_!=NULL);
00312     memcpy(lower_,rhs.lower_,numberIntegers_*sizeof(int));
00313     memcpy(upper_,rhs.upper_,numberIntegers_*sizeof(int));
00314   }
00315 }
00316 
00317 OsiNodeSimple &
00318 OsiNodeSimple::operator=(const OsiNodeSimple & rhs)
00319 {
00320   if (this != &rhs) {
00321     basis_=rhs.basis_;
00322     objectiveValue_=rhs.objectiveValue_;
00323     variable_=rhs.variable_;
00324     way_=rhs.way_;
00325     numberIntegers_=rhs.numberIntegers_;
00326     value_=rhs.value_;
00327     delete [] lower_;
00328     delete [] upper_;
00329     lower_=NULL;
00330     upper_=NULL;
00331     if (rhs.lower_!=NULL) {
00332       lower_ = new int [numberIntegers_];
00333       upper_ = new int [numberIntegers_];
00334       assert (upper_!=NULL);
00335       memcpy(lower_,rhs.lower_,numberIntegers_*sizeof(int));
00336       memcpy(upper_,rhs.upper_,numberIntegers_*sizeof(int));
00337     }
00338   }
00339   return *this;
00340 }
00341 
00342 
00343 OsiNodeSimple::~OsiNodeSimple ()
00344 {
00345   delete [] lower_;
00346   delete [] upper_;
00347 }
00348 
00349 #include <vector>
00350 
00351 // Vector of OsiNodeSimples 
00352 typedef std::vector<OsiNodeSimple>    OsiVectorNode;
00353 
00354 //#############################################################################
00355 
00356 #ifdef NDEBUG
00357 #undef NDEBUG
00358 #endif
00359 class OsiOslMessageTest :
00360    public CoinMessageHandler {
00361 
00362 public:
00363   virtual int print() ;
00364 };
00365 
00366 int
00367 OsiOslMessageTest::print()
00368 {
00369   static int numberOptimal=0,numberInfeasible=0;
00370   if (currentSource()=="Osl") {
00371     if (currentMessage().externalNumber()==1) { 
00372       numberOptimal++;
00373       if (numberOptimal%100==0)
00374         return CoinMessageHandler::print(); // print
00375     } else if (currentMessage().externalNumber()==3000) { 
00376       numberInfeasible++;
00377     }
00378   }  else if (currentSource()=="Osi") {
00379     if (currentMessage().externalNumber()==5) 
00380       std::cout<<"End of search trapped, "
00381                <<numberOptimal<<" optimal Lp's, "
00382                <<numberInfeasible
00383                <<" infeasible (including strong branching)"<<std::endl;
00384     return CoinMessageHandler::print();
00385   }
00386   return 0;
00387 }
00388 #include <stdio.h>
00389 // OSL function to trap messages
00390 extern "C" void trapMessages(EKKModel * model, int  msgno, int nreal,
00391                             double * rvec, int nint, int * ivec,
00392                             int nchar, char * cvec)
00393 {
00394   // break out message (assumes prefix there)
00395   char severity = cvec[nchar*128+8];
00396   char mainPart[153];
00397   strncpy(mainPart,cvec+nchar*128+9,152);
00398   mainPart[152]='\0';
00399   int length = strlen(mainPart);
00400   int i;
00401   for (i=length-1;i>=0;i--) {
00402     if (mainPart[i]!=' '&&mainPart[i]!='\t')
00403       break;
00404   }
00405   if (i>=0) {
00406     mainPart[i+1]='\0';
00407     CoinMessageHandler * handler =  (CoinMessageHandler *) ekk_userData(model);
00408     handler->message(msgno,"Osl",mainPart,severity);
00409     for (i=0;i<nreal;i++) 
00410       *handler<<rvec[i];
00411     for (i=0;i<nint;i++) 
00412       *handler<<ivec[i];
00413     for (i=0;i<nchar;i++) 
00414       *handler<<cvec+128*i;
00415     handler->finish();
00416   }
00417   return;
00418 }
00419 //--------------------------------------------------------------------------
00420 // test EKKsolution methods.
00421 void
00422 OsiOslSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir)
00423 {
00424 
00425   // Test default constructor
00426   {
00427     assert( OsiOslSolverInterface::getNumInstances()==0 );
00428     OsiOslSolverInterface m;
00429     assert( m.modelPtr_==NULL );
00430     assert( m.rowsense_==NULL );
00431     assert( m.rhs_==NULL );
00432     assert( m.rowrange_==NULL );
00433     assert( m.matrixByRow_==NULL );
00434     assert( m.matrixByColumn_==NULL );
00435     assert( OsiOslSolverInterface::getNumInstances()==1 );
00436     assert( m.getApplicationData() == NULL );
00437     int i=2346;
00438     m.setApplicationData(&i);
00439     assert( *((int *)(m.getApplicationData())) == i );
00440   }
00441   assert( OsiOslSolverInterface::getNumInstances()==0 );
00442 
00443   
00444   {    
00445     CoinRelFltEq eq;
00446     OsiOslSolverInterface m;
00447     assert( OsiOslSolverInterface::getNumInstances()==1 );
00448     std::string fn = mpsDir+"exmip1";
00449     m.readMps(fn.c_str(),"mps");
00450     int ad = 13579;
00451     m.setApplicationData(&ad);
00452     assert( *((int *)(m.getApplicationData())) == ad );
00453     
00454     {
00455       OsiOslSolverInterface im;    
00456       assert( im.modelPtr_==NULL );
00457       
00458       assert( im.getNumCols() == 0 ); 
00459       
00460       assert( im.getModelPtr()!=NULL );
00461       assert( im.getMutableModelPtr()!=NULL );
00462       assert( im.getModelPtr() == im.getMutableModelPtr() );
00463     }
00464     
00465     // Test copy constructor and assignment operator
00466     {
00467       OsiOslSolverInterface lhs;
00468       {      
00469         assert( *((int *)(m.getApplicationData())) == ad );
00470         OsiOslSolverInterface im(m);        
00471         assert( *((int *)(im.getApplicationData())) == ad );
00472 
00473         OsiOslSolverInterface imC1(im);
00474         assert( imC1.getMutableModelPtr()!=im.getMutableModelPtr() );
00475         assert( imC1.getModelPtr()!=im.getModelPtr() );
00476         assert( imC1.getNumCols() == im.getNumCols() );
00477         assert( imC1.getNumRows() == im.getNumRows() );   
00478         assert( *((int *)(imC1.getApplicationData())) == ad ); 
00479         
00480         //im.setModelPtr(m);
00481         
00482         
00483         OsiOslSolverInterface imC2(im);
00484         assert( imC2.getMutableModelPtr()!=im.getMutableModelPtr() );
00485         assert( imC2.getModelPtr()!=im.getModelPtr() );
00486         assert( imC2.getNumCols() == im.getNumCols() );
00487         assert( imC2.getNumRows() == im.getNumRows() );  
00488         assert( *((int *)(imC2.getApplicationData())) == ad ); 
00489         
00490         assert( imC2.getMutableModelPtr()!=imC1.getMutableModelPtr() );
00491         assert( imC2.getModelPtr()!=imC1.getModelPtr() );
00492         
00493         lhs=imC2;
00494       }
00495       // Test that lhs has correct values even though rhs has gone out of scope
00496       
00497       assert( lhs.getMutableModelPtr() != m.getMutableModelPtr() );
00498       assert( lhs.getModelPtr() != m.getModelPtr() );
00499       assert( lhs.getNumCols() == m.getNumCols() );
00500       assert( lhs.getNumRows() == m.getNumRows() );      
00501       assert( *((int *)(lhs.getApplicationData())) == ad );
00502     }
00503     
00504     // Test clone
00505     {
00506       OsiOslSolverInterface oslSi(m);
00507       OsiSolverInterface * siPtr = &oslSi;
00508       OsiSolverInterface * siClone = siPtr->clone();
00509       OsiOslSolverInterface * oslClone = dynamic_cast<OsiOslSolverInterface*>(siClone);
00510       assert( oslClone != NULL );
00511       assert( oslClone->getModelPtr() != oslSi.getModelPtr() );
00512       assert( oslClone->getModelPtr() != m.getModelPtr() );
00513       assert( oslClone->getNumRows() == oslSi.getNumRows() );
00514       assert( oslClone->getNumCols() == m.getNumCols() );
00515       
00516       assert( *((int *)(oslClone->getApplicationData())) == ad );
00517       // Test reset
00518       siClone->reset();
00519       assert( oslClone->rowsense_==NULL );
00520       assert( oslClone->rhs_==NULL );
00521       assert( oslClone->rowrange_==NULL );
00522       assert( oslClone->matrixByRow_==NULL );
00523       assert( oslClone->ws_==NULL);
00524       assert( oslClone->itlimOrig_==9999999);
00525       delete siClone;
00526     }
00527    
00528     // test infinity
00529     {
00530       OsiOslSolverInterface si;
00531       assert( eq(si.getInfinity(),OSL_INFINITY));
00532     }     
00533 
00534     //--------------
00535     // Test rowsense, rhs, rowrange, matrixByRow
00536     {
00537       OsiOslSolverInterface lhs;
00538       {      
00539         assert( m.rowrange_==NULL );
00540         assert( m.rowsense_==NULL );
00541         assert( m.rhs_==NULL );
00542         assert( m.matrixByRow_==NULL );
00543         
00544         OsiOslSolverInterface siC1(m);     
00545         assert( siC1.rowrange_==NULL );
00546         assert( siC1.rowsense_==NULL );
00547         assert( siC1.rhs_==NULL );
00548         assert( siC1.matrixByRow_==NULL );
00549 
00550         const char   * siC1rs  = siC1.getRowSense();
00551         assert( siC1rs[0]=='G' );
00552         assert( siC1rs[1]=='L' );
00553         assert( siC1rs[2]=='E' );
00554         assert( siC1rs[3]=='R' );
00555         assert( siC1rs[4]=='R' );
00556         
00557         const double * siC1rhs = siC1.getRightHandSide();
00558         assert( eq(siC1rhs[0],2.5) );
00559         assert( eq(siC1rhs[1],2.1) );
00560         assert( eq(siC1rhs[2],4.0) );
00561         assert( eq(siC1rhs[3],5.0) );
00562         assert( eq(siC1rhs[4],15.) ); 
00563         
00564         const double * siC1rr  = siC1.getRowRange();
00565         assert( eq(siC1rr[0],0.0) );
00566         assert( eq(siC1rr[1],0.0) );
00567         assert( eq(siC1rr[2],0.0) );
00568         assert( eq(siC1rr[3],5.0-1.8) );
00569         assert( eq(siC1rr[4],15.0-3.0) );
00570         
00571         const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow();
00572         assert( siC1mbr != NULL );
00573         
00574         const double * ev = siC1mbr->getElements();
00575         assert( eq(ev[0],   3.0) );
00576         assert( eq(ev[1],   1.0) );
00577         assert( eq(ev[2],  -2.0) );
00578         assert( eq(ev[3],  -1.0) );
00579         assert( eq(ev[4],  -1.0) );
00580         assert( eq(ev[5],   2.0) );
00581         assert( eq(ev[6],   1.1) );
00582         assert( eq(ev[7],   1.0) );
00583         assert( eq(ev[8],   1.0) );
00584         assert( eq(ev[9],   2.8) );
00585         assert( eq(ev[10], -1.2) );
00586         assert( eq(ev[11],  5.6) );
00587         assert( eq(ev[12],  1.0) );
00588         assert( eq(ev[13],  1.9) );
00589         
00590         const int * mi = siC1mbr->getVectorStarts();
00591         assert( mi[0]==0 );
00592         assert( mi[1]==5 );
00593         assert( mi[2]==7 );
00594         assert( mi[3]==9 );
00595         assert( mi[4]==11 );
00596         assert( mi[5]==14 );
00597         
00598         const int * ei = siC1mbr->getIndices();
00599         assert( ei[0]  ==  0 );
00600         assert( ei[1]  ==  1 );
00601         assert( ei[2]  ==  3 );
00602         assert( ei[3]  ==  4 );
00603         assert( ei[4]  ==  7 );
00604         assert( ei[5]  ==  1 );
00605         assert( ei[6]  ==  2 );
00606         assert( ei[7]  ==  2 );
00607         assert( ei[8]  ==  5 );
00608         assert( ei[9]  ==  3 );
00609         assert( ei[10] ==  6 );
00610         assert( ei[11] ==  0 );
00611         assert( ei[12] ==  4 );
00612         assert( ei[13] ==  7 );    
00613         
00614         assert( siC1mbr->getMajorDim() == 5 ); 
00615         assert( siC1mbr->getNumElements() == 14 );
00616         
00617 
00618         assert( siC1rs  == siC1.getRowSense() );
00619         assert( siC1rhs == siC1.getRightHandSide() );
00620         assert( siC1rr  == siC1.getRowRange() );
00621 
00622         // Change OSL Model by adding free row
00623         OsiRowCut rc;
00624         rc.setLb(-DBL_MAX);
00625         rc.setUb( DBL_MAX);
00626         OsiCuts cuts;
00627         cuts.insert(rc);
00628         siC1.applyCuts(cuts);
00629              
00630         // Since model was changed, test that cached
00631         // data is now freed.
00632         assert( siC1.rowrange_==NULL );
00633         assert( siC1.rowsense_==NULL );
00634         assert( siC1.rhs_==NULL );
00635         assert( siC1.matrixByRow_==NULL );
00636         
00637         siC1rs  = siC1.getRowSense();
00638         assert( siC1rs[0]=='G' );
00639         assert( siC1rs[1]=='L' );
00640         assert( siC1rs[2]=='E' );
00641         assert( siC1rs[3]=='R' );
00642         assert( siC1rs[4]=='R' );
00643         assert( siC1rs[5]=='N' );
00644 
00645         siC1rhs = siC1.getRightHandSide();
00646         assert( eq(siC1rhs[0],2.5) );
00647         assert( eq(siC1rhs[1],2.1) );
00648         assert( eq(siC1rhs[2],4.0) );
00649         assert( eq(siC1rhs[3],5.0) );
00650         assert( eq(siC1rhs[4],15.) ); 
00651         assert( eq(siC1rhs[5],0.0 ) ); 
00652 
00653         siC1rr  = siC1.getRowRange();
00654         assert( eq(siC1rr[0],0.0) );
00655         assert( eq(siC1rr[1],0.0) );
00656         assert( eq(siC1rr[2],0.0) );
00657         assert( eq(siC1rr[3],5.0-1.8) );
00658         assert( eq(siC1rr[4],15.0-3.0) );
00659         assert( eq(siC1rr[5],0.0) );
00660     
00661         lhs=siC1;
00662       }
00663       // Test that lhs has correct values even though siC1 has gone out of scope    
00664       assert( lhs.rowrange_==NULL );
00665       assert( lhs.rowsense_==NULL );
00666       assert( lhs.rhs_==NULL ); 
00667       assert( lhs.matrixByRow_==NULL ); 
00668       
00669       const char * lhsrs  = lhs.getRowSense();
00670       assert( lhsrs[0]=='G' );
00671       assert( lhsrs[1]=='L' );
00672       assert( lhsrs[2]=='E' );
00673       assert( lhsrs[3]=='R' );
00674       assert( lhsrs[4]=='R' );
00675       assert( lhsrs[5]=='N' );
00676       
00677       const double * lhsrhs = lhs.getRightHandSide();
00678       assert( eq(lhsrhs[0],2.5) );
00679       assert( eq(lhsrhs[1],2.1) );
00680       assert( eq(lhsrhs[2],4.0) );
00681       assert( eq(lhsrhs[3],5.0) );
00682       assert( eq(lhsrhs[4],15.) ); 
00683       assert( eq(lhsrhs[5],0.0) ); 
00684       
00685       const double *lhsrr  = lhs.getRowRange();
00686       assert( eq(lhsrr[0],0.0) );
00687       assert( eq(lhsrr[1],0.0) );
00688       assert( eq(lhsrr[2],0.0) );
00689       assert( eq(lhsrr[3],5.0-1.8) );
00690       assert( eq(lhsrr[4],15.0-3.0) );
00691       assert( eq(lhsrr[5],0.0) );      
00692       
00693       const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow();
00694       assert( lhsmbr != NULL );       
00695       const double * ev = lhsmbr->getElements();
00696       assert( eq(ev[0],   3.0) );
00697       assert( eq(ev[1],   1.0) );
00698       assert( eq(ev[2],  -2.0) );
00699       assert( eq(ev[3],  -1.0) );
00700       assert( eq(ev[4],  -1.0) );
00701       assert( eq(ev[5],   2.0) );
00702       assert( eq(ev[6],   1.1) );
00703       assert( eq(ev[7],   1.0) );
00704       assert( eq(ev[8],   1.0) );
00705       assert( eq(ev[9],   2.8) );
00706       assert( eq(ev[10], -1.2) );
00707       assert( eq(ev[11],  5.6) );
00708       assert( eq(ev[12],  1.0) );
00709       assert( eq(ev[13],  1.9) );
00710       
00711       const int * mi = lhsmbr->getVectorStarts();
00712       assert( mi[0]==0 );
00713       assert( mi[1]==5 );
00714       assert( mi[2]==7 );
00715       assert( mi[3]==9 );
00716       assert( mi[4]==11 );
00717       assert( mi[5]==14 );
00718       
00719       const int * ei = lhsmbr->getIndices();
00720       assert( ei[0]  ==  0 );
00721       assert( ei[1]  ==  1 );
00722       assert( ei[2]  ==  3 );
00723       assert( ei[3]  ==  4 );
00724       assert( ei[4]  ==  7 );
00725       assert( ei[5]  ==  1 );
00726       assert( ei[6]  ==  2 );
00727       assert( ei[7]  ==  2 );
00728       assert( ei[8]  ==  5 );
00729       assert( ei[9]  ==  3 );
00730       assert( ei[10] ==  6 );
00731       assert( ei[11] ==  0 );
00732       assert( ei[12] ==  4 );
00733       assert( ei[13] ==  7 );    
00734       
00735       int md = lhsmbr->getMajorDim();
00736       assert(  md == 6 ); 
00737       assert( lhsmbr->getNumElements() == 14 );
00738     }
00739     
00740     assert(OsiOslSolverInterface::getNumInstances()==1);
00741   }
00742   assert(OsiOslSolverInterface::getNumInstances()==0);
00743 
00744   // Do common solverInterface testing 
00745   {
00746     OsiOslSolverInterface m;
00747     OsiSolverInterfaceCommonUnitTest(&m, mpsDir, netlibDir );
00748   }
00749 
00750   // Do primitive branch and bound
00751   // And test message handling
00752   /* This could be moved down to OsiSolverInterface by
00753      putting in branchAndBound and taking off m.
00754   */
00755   int iPass;
00756   for (iPass=0;iPass<2;iPass++) {
00757     OsiOslSolverInterface m;
00758     std::string fn = mpsDir+"p0033";
00759     m.readMps(fn.c_str(),"mps");
00760      // derived message handler (only used on second pass)
00761     OsiOslMessageTest messageHandler;
00762    if (iPass) {
00763       std::cout<<"Testing derived message handler"<<std::endl;
00764       m.passInMessageHandler(&messageHandler);
00765       ekk_registerMsguCallBack(m.getModelPtr(),trapMessages);
00766       // say all messages to be trapped
00767       ekk_mset(m.getModelPtr(),1,0,-1,2,9999,0);
00768       // pass handler to OSL
00769       ekk_setUserData(m.getModelPtr(),&messageHandler);
00770    }
00771     // solve LP
00772     m.initialSolve();
00773     // setColBounds prints every time - don't even get to message handler
00774     ekk_messagePrintOff(m.getModelPtr() ,317);
00775     ekk_messagePrintOff(m.getModelPtr() ,318);
00776     ekk_messagePrintOff(m.getModelPtr() ,3048);
00777     ekk_messagePrintOff(m.getModelPtr() ,85);
00778     ekk_messagePrintOff(m.getModelPtr() ,82);
00779     ekk_messagePrintOff(m.getModelPtr() ,38);
00780 
00781     if (m.isProvenOptimal()&&!m.isDualObjectiveLimitReached()) {
00782       // This is a really simple Branch and Bound code - mainly
00783       // to test strong branching
00784       // I should look at STL more to allow other than depth first
00785       int numberIntegers=0;
00786       int numberColumns = m.getNumCols();
00787       int iColumn;
00788       int i;
00789       for (iColumn=0;iColumn<numberColumns;iColumn++) {
00790         if( m.isInteger(iColumn))
00791           numberIntegers++;
00792       }
00793       if (!numberIntegers) {
00794         std::cout<<"No integer variables"
00795           <<std::endl;
00796         return;
00797       }
00798       int * which = new int[numberIntegers]; // which variables are integer
00799       numberIntegers=0;
00800       for (iColumn=0;iColumn<numberColumns;iColumn++) {
00801         if( m.isInteger(iColumn))
00802           which[numberIntegers++]=iColumn;
00803       }
00804       
00805       // empty tree
00806       OsiVectorNode branchingTree;
00807       
00808       // Add continuous to it;
00809       branchingTree.push_back(OsiNodeSimple(m,numberIntegers,which));
00810       
00811       // For printing totals
00812       int numberIterations=0;
00813       int numberNodes =0;
00814       
00815       OsiNodeSimple bestNode;
00816       // while until nothing on stack
00817       while (branchingTree.size()) {
00818         // last node
00819         OsiNodeSimple node = branchingTree.back();
00820         branchingTree.pop_back();
00821         numberNodes++;
00822         if (node.variable_>=0) {
00823           // branch - do bounds
00824           for (i=0;i<numberIntegers;i++) {
00825             iColumn=which[i];
00826             m.setColBounds( iColumn,node.lower_[i],node.upper_[i]);
00827           }
00828           // move basis
00829           m.setWarmStart(&node.basis_);
00830           // do branching variable
00831           if (node.way_<0) {
00832             m.setColUpper(which[node.variable_],floor(node.value_));
00833             // now push back node if more to come
00834             if (node.way_==-1) { 
00835               node.way_=+2;       // Swap direction
00836               branchingTree.push_back(node);
00837             }
00838           } else {
00839             m.setColLower(which[node.variable_],ceil(node.value_));
00840             // now push back node if more to come
00841             if (node.way_==1) { 
00842               node.way_=-2;       // Swap direction
00843               branchingTree.push_back(node);
00844             }
00845           }
00846           // solve
00847           m.resolve();
00848           numberIterations += m.getIterationCount();
00849           if (!m.isIterationLimitReached()) {
00850             OsiNodeSimple newNode(m,numberIntegers,which);
00851             // something extra may have been fixed by strong branching
00852             // if so go round again
00853             while (newNode.variable_==numberIntegers) {
00854               m.resolve();
00855               newNode = OsiNodeSimple(m,numberIntegers,which);
00856             }
00857             if (newNode.objectiveValue_<1.0e100) {
00858               // push on stack
00859               branchingTree.push_back(newNode);
00860             }
00861           } else {
00862             // maximum iterations - exit
00863             std::cout<<"Exiting on maximum iterations"
00864               <<std::endl;
00865           break;
00866           }
00867         } else {
00868           // integer solution - save
00869           bestNode = node;
00870           // set cutoff (hard coded tolerance)
00871           m.setDblParam(OsiDualObjectiveLimit,bestNode.objectiveValue_-1.0e-5);
00872           std::cout<<"Integer solution of "
00873                    <<bestNode.objectiveValue_
00874                    <<" found after "<<numberIterations
00875                    <<" iterations and "<<numberNodes<<" nodes"
00876                    <<std::endl;
00877         }
00878       }
00879       std::cout<<"Search took "
00880                <<numberIterations
00881                <<" iterations and "<<numberNodes<<" nodes"
00882                <<std::endl;
00883       if (bestNode.numberIntegers_) {
00884         // we have a solution restore
00885         // do bounds
00886         for (i=0;i<numberIntegers;i++) {
00887           iColumn=which[i];
00888           m.setColBounds( iColumn,bestNode.lower_[i],bestNode.upper_[i]);
00889         }
00890         // move basis
00891         m.setWarmStart(&bestNode.basis_);
00892         m.resolve();
00893       }
00894       delete [] which;
00895     } else {
00896       std::cout<<"The LP relaxation is infeasible"
00897                <<std::endl;
00898       throw CoinError("The LP relaxation is infeasible or too expensive",
00899                       "branchAndBound", "OsiClpSolverInterface");
00900     }
00901     ekk_messagePrintOn(m.getModelPtr() ,317);
00902     ekk_messagePrintOn(m.getModelPtr() ,318);
00903     ekk_messagePrintOn(m.getModelPtr() ,3048);
00904     ekk_messagePrintOn(m.getModelPtr() ,85);
00905     ekk_messagePrintOn(m.getModelPtr() ,82);
00906     ekk_messagePrintOn(m.getModelPtr() ,38);
00907     // Very important to normalize before going out of scope
00908     ekk_clearMsguCallBack(m.getModelPtr());
00909     ekk_setUserData(m.getModelPtr(),NULL);
00910    }
00911 
00912   assert(OsiOslSolverInterface::getNumInstances()==0);
00913 
00914 }

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