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

CglSimpleRounding.cpp

00001 // Copyright (C) 2000, International Business Machines
00002 // Corporation and others.  All Rights Reserved.
00003 #if defined(_MSC_VER)
00004 // Turn off compiler warning about long names
00005 #  pragma warning(disable:4786)
00006 #endif
00007 #include <cstdlib>
00008 #include <cmath>
00009 #include <cstdio>
00010 #include <cfloat> 
00011 #include <cassert>
00012 
00013 #include "CglSimpleRounding.hpp" 
00014 #include "CoinPackedVector.hpp"
00015 #include "CoinSort.hpp"
00016 #include "CoinPackedMatrix.hpp"
00017 
00018 //-------------------------------------------------------------
00019 void
00020 CglSimpleRounding::generateCuts(const OsiSolverInterface & si, 
00021                                             OsiCuts & cs) const
00022 {
00023   int nRows=si.getNumRows(); // number of rows in the coefficient matrix
00024   int nCols=si.getNumCols(); // number of columns in the coefficient matrix
00025   int rowIndex;             // index into the constraint matrix stored in row
00026                             // order 
00027   CoinPackedVector irow;     // "integer row": working space to hold the integer
00028                             // <= inequality derived from the rowIndex-th
00029                             // constraint 
00030   double b=0;             // working space for the rhs of integer <= inequality
00031   bool * negative= new bool[nCols]; // negative[i]= true if coefficient of the 
00032                                     // ith variable is negative and false
00033                                     // otherwise 
00034   int k;                  // dummy iterator variable 
00035   for ( k=0; k<nCols; k++ ) negative[k] = false;
00036   
00037   const CoinPackedMatrix * rowCopy = 
00038     si.getMatrixByRow(); // row copy: matrix stored in row order
00039 
00041   // Main loop:                                                              //
00042   // For every row in the matrix,                                            //
00043   //     if we can derive a valid <= inequality in integer variables, then   //
00044   //     try to construct a simple rounding cut from the integer inequality. //
00045   //     Add the resulting cut to the set of cuts.                           //
00047 
00048   for (rowIndex=0; rowIndex<nRows; rowIndex++){
00049 
00050     // Only look at tight rows
00051     // double * pi=ekk_rowduals(model); 
00052     // if (fabs(pi[row]) < epsilon_){
00053    //  continue;
00054     // }
00055 
00056     // Try to derive an <= inequality in integer variables from the row 
00057     // by netting out the continuous variables.
00058     // Store the value and the sign of the coefficients separately:
00059     // irow.getElements() contains the absolute values of the coefficients.
00060     // negative is a boolean vector indicating the sign of the coeffcients.
00061     // b is the rhs of the <= integer inequality
00062 
00063     if (!deriveAnIntegerRow( si, 
00064                              rowIndex, 
00065                              rowCopy->getVector(rowIndex),
00066                              irow, b, negative))
00067     {
00068 
00069       // Reset local data for the next iteration of the rowIndex-loop
00070       for(k=0; k<irow.getNumElements(); k++) negative[irow.getIndices()[k]]=false;
00071       irow.setVector(0,NULL,NULL);
00072       continue;
00073     } 
00074  
00075     // Euclid's greatest common divisor (gcd) algorithm applies to positive
00076     // INTEGERS. 
00077     // Determine the power of 10 needed, so that multipylying the integer
00078     // inequality through by 10**power makes all coefficients essentially
00079     // integral. 
00080     int power = power10ToMakeDoubleAnInt(irow.getNumElements(),irow.getElements(),epsilon_*1.0e-4);
00081 
00082     // Now a vector to store the integer-ized values. For instance, 
00083     // if x[i] is .66 and power is 1000 then xInt[i] will be 660
00084     int * xInt = NULL;
00085     if (power >=0) {
00086 
00087       xInt = new int[irow.getNumElements()]; 
00088       double dxInt; // a double version of xInt for error trapping
00089       
00090       
00091 #ifdef CGL_DEBUG      
00092       printf("The (double) coefficients and their integer-ized counterparts:\n");
00093 #endif
00094 
00095       for (k=0; k<irow.getNumElements(); k++){
00096         dxInt = irow.getElements()[k]*pow(10.0,power);
00097         xInt[k]= (int) (dxInt+0.5); // Need to add the 0.5 
00098         // so that a dxInt=9.999 will give a xInt=1
00099 
00100 #ifdef CGL_DEBUG
00101         printf("%g     %g   \n",irow.getElements()[k],dxInt);
00102 #endif
00103 
00104       }
00105 
00106     } else {
00107 
00108       // If overflow is detected, one warning message is printed and 
00109       // the row is skipped.
00110 #ifdef CGL_DEBUG
00111       printf("SimpleRounding: Warning: Overflow detected \n");
00112       printf("      on %i of vars in processing row %i. Row skipped.\n",
00113              -power, rowIndex);
00114 #endif
00115       // reset local data for next iteration
00116       for(k=0; k<irow.getNumElements(); k++) negative[irow.getIndices()[k]]=false;
00117       irow.setVector(0,NULL,NULL);
00118       continue;
00119     }
00120 
00121     // find greatest common divisor of the irow.elements
00122     int gcd = gcdv(irow.getNumElements(), xInt);
00123 
00124 #ifdef CGL_DEBUG
00125     printf("The gcd of xInt is %i\n",gcd);    
00126 #endif
00127 
00128     // construct new cut by dividing through by gcd and 
00129     // rounding down rhs and accounting for negatives
00130     CoinPackedVector cut;
00131     for (k=0; k<irow.getNumElements(); k++){
00132         cut.insert(irow.getIndices()[k],xInt[k]/gcd);
00133     }
00134     double cutRhs = floor((b*pow(10.0,power))/gcd);
00135 
00136     // un-negate the negated variables in the cut
00137     {
00138        const int s = cut.getNumElements();
00139        const int * indices = cut.getIndices();
00140        double* elements = cut.getElements();
00141        for (k=0; k<s; k++){
00142          int column=indices[k];
00143           if (negative[column]) {
00144              elements[k] *= -1;
00145           }
00146        }
00147     }
00148 
00149     // Create the row cut and add it to the set of cuts
00150     // It may not be violated
00151     if (fabs(cutRhs*gcd-b)> epsilon_){ // if the cut and row are different. 
00152       OsiRowCut rc;
00153       rc.setRow(cut.getNumElements(),cut.getIndices(),cut.getElements());
00154       rc.setLb(-DBL_MAX);
00155       rc.setUb(cutRhs);   
00156       cs.insert(rc);
00157 
00158 #ifdef CGL_DEBUG
00159       printf("Row %i had a simple rounding cut:\n",rowIndex);
00160       printf("Cut size: %i Cut rhs: %g  Index       Element \n",
00161              cut.getNumElements(), cutRhs);
00162       for (k=0; k<cut.getNumElements(); k++){
00163         printf("%i      %g\n",cut.getIndices()[k], cut.getElements()[k]);
00164       }
00165       printf("\n");
00166 #endif
00167     }
00168 
00169     // Reset local data for the next iteration of the rowIndex-loop
00170     for(k=0; k<irow.getNumElements(); k++) negative[irow.getIndices()[k]]=false;
00171     irow.setVector(0,NULL,NULL);
00172     delete [] xInt;
00173 
00174 
00175   }
00176 
00177   delete [] negative;
00178 }
00179 
00180 
00181 //-------------------------------------------------------------------
00182 // deriveAnIntegerRow:  dervies a <=  inequality
00183 //                  in integer variables of the form ax<=b 
00184 //                  from a row in the model, if possible by
00185 //                  netting out the continuous variables
00186 //-------------------------------------------------------------------
00187 bool
00188 CglSimpleRounding::deriveAnIntegerRow(
00189        const OsiSolverInterface & si, 
00190        int rowIndex,
00191        const CoinShallowPackedVector & matrixRow,
00192        CoinPackedVector & irow, 
00193        double & b,
00194        bool * negative) const
00195 {
00196   irow.clear();
00197   int i;           // dummy iterator variable
00198   double sign=1.0; // +1 if le row, -1 if ge row  
00199 
00200   // number of columns in the row
00201   int sizeOfRow=matrixRow.getNumElements();
00202 
00203   // Get the sense of the row constraint
00204   const char  rowsense = si.getRowSense()[rowIndex];
00205 
00206   // Skip equality rows  
00207   if  (rowsense=='E' || rowsense=='N') {
00208     return 0; 
00209   }
00210   // le row  
00211   if (rowsense=='L'){
00212     b=si.getRightHandSide()[rowIndex];
00213   }
00214   // ge row
00215   // Multiply through by -1 to convert it to a le row 
00216   if (rowsense=='G'){
00217     b=-si.getRightHandSide()[rowIndex];
00218     sign=-1.0;
00219   }
00220   
00221   // Finite, but unequal row bounds  
00222   // Could derive an simple rounding inequality from either 
00223   // (or from both!) but for expediency, 
00224   // use the le relationship as the default for now  
00225   if  (rowsense=='R') {
00226     b=si.getRightHandSide()[rowIndex];
00227   }
00228   
00229    // Try to net out the continuous variables from the constraint.
00230   // Multipy through by sign to convert the inequality to a le inequality  
00231   // If the coefficient on a continuous variable is positive, replace
00232   // the continous variable with its lower bound 
00233   // If the coefficient on a continuous variable is negative, replace
00234   // the continuous variable with its upper bound.
00235   // example:
00236   //                   2.5 <= 3x0-2.8x1+4x2,  0<=x0<=0.2, 0.4<=x1, x2 integer
00237   //                         -3x0+2.8x1-4x2 <= -2.5
00238   // -3(0.2)+2.8(0.4)-4x3 <= -3x0+2.8x1-4x2 <= -2.5
00239   // gives the (weaker, valid) integer inequality
00240   //                                   -4x2 <= -2.5+3(0.2)-2.8(0.4)
00241   // sign = -1
00242   // irow.elements = 4
00243   // irow.indices = 2
00244   // negative = (true, true, false)
00245   // b=-2.5+3(0.2)-2.8(0.4)= -3.02
00246 
00247   const double * colupper = si.getColUpper();
00248   const double * collower = si.getColLower();
00249 
00250   for (i=0; i<sizeOfRow; i++){
00251     // if the variable is continuous
00252     if ( !si.isInteger( matrixRow.getIndices()[i] ) ) {
00253       // and the coefficient is strictly negative
00254       if((sign*matrixRow.getElements()[i])<-epsilon_){
00255         // and the continuous variable has a fintite upper bound
00256         if (colupper[matrixRow.getIndices()[i]] < si.getInfinity()){
00257           // then replace the variable with its upper bound.
00258           b=b-(sign*matrixRow.getElements()[i]*colupper[matrixRow.getIndices()[i]]);
00259         } 
00260         else 
00261           return 0;
00262       }
00263       // if the coefficient in strictly positive
00264       else if((sign*matrixRow.getElements()[i])>epsilon_){
00265         // and the continuous variable has a finite lower bound
00266         if (collower[matrixRow.getIndices()[i]] > -si.getInfinity()){
00267           // then replace the variable with its lower bound.
00268           b=b-(sign*matrixRow.getElements()[i]*collower[matrixRow.getIndices()[i]]);
00269         }
00270         else
00271           return 0;
00272       }
00273       // else the coefficient is essentially an explicitly stored zero; do
00274       // nothing   
00275     }
00276     // else: the variable is integer
00277     else{
00278       // if the integer variable is fixed, net it out of the integer inequality
00279       if (colupper[matrixRow.getIndices()[i]]- collower[matrixRow.getIndices()[i]]<
00280           epsilon_){
00281           b=b-(sign*matrixRow.getElements()[i]*colupper[matrixRow.getIndices()[i]]);
00282       }
00283       // else the variable is a free integer variable and it becomes
00284       // part of the integer inequality
00285       else {
00286         irow.insert(matrixRow.getIndices()[i],sign*matrixRow.getElements()[i]);
00287       }
00288     }
00289   }
00290   
00291   // if there are no free integer variables, then abandon this row;
00292   if(irow.getNumElements() == 0){
00293     return 0;
00294   }
00295   
00296   // Store the values and the signs of the coefficients separately.
00297   // irow.elements stores the absolute values of the coefficients
00298   // negative indicates the sign.
00299   // Note: after this point b is essentially the effecitve rhs of a le
00300   // contraint
00301   {
00302      const int s = irow.getNumElements();
00303      const int * indices = irow.getIndices();
00304      double * elements = irow.getElements();
00305      for(i=0; i<s; i++){
00306         if (elements[i] < -epsilon_) {
00307            negative[indices[i]]= true; // store indicator of the sign 
00308            elements[i] *= -1;          // store only positive values
00309         }
00310     }
00311   }
00312 
00313   return 1;
00314 }
00315 
00316 
00317 //-------------------------------------------------------------------
00318 // power10ToMakeDoubleAnInt: 
00319 //   given a vector of positive doubles x_i, i=1, size, and a positive
00320 //   tolerance dataTol, determine the smallest power of 10 needed so that
00321 //   x[i]*10**power is integer for all i.
00322 
00323 //   dataTol_ should be correlated to the accuracy of the data,
00324 //   and choosen to be the largest value that's tolerable.
00325 //   
00326 //   (Easily extended to take an input vector of arbitrary sign)
00327 //-------------------------------------------------------------------
00328 //
00329 int
00330 CglSimpleRounding::power10ToMakeDoubleAnInt( 
00331     int size,             // the length of the input vector x
00332     const double * x,     // the input vector of postive values  
00333     double dataTol) const // the (strictly postive) precision of the data
00334 
00335 {
00336   // Assumption: data precision is positive
00337   assert( dataTol > 0 );
00338 
00339 
00340   int i;           // loop iterator 
00341   int maxPower=0;  // maximum power of 10 used to convert any x[i] to an
00342                    // integer 
00343                    // this is the number we are after.
00344   int power = 0;   // power of 10 used to convert a particular x[i] to an
00345                    // integer 
00346 
00347 #ifdef OLD_MULT
00348   double intPart;  // the integer part of the number
00349 #endif
00350   double fracPart; // the fractional part of the number
00351                    // we keep multiplying by 10 until the fractional part is 0
00352                    // (well, really just until the factional part is less than
00353                    // dataTol) 
00354 
00355   // JJF - code seems to fail sometimes as multiplying by 10 - so
00356   // definition of dataTol changed - see header file
00357 
00358   const double multiplier[16]={1.0,1.0e1,1.0e2,1.0e3,1.0e4,1.0e5,
00359                                1.0e6,1.0e7,1.0e8,1.0e9,1.0e10,1.0e11,
00360                                1.0e12,1.0e13,1.0e14,1.0e15};
00361 
00362   // Loop through every element in the array in x
00363   for (i=0; i<size; i++){
00364     power = 0;
00365 
00366 #ifdef OLD_MULT 
00367     // look at the fractional part of x[i]
00368     // FYI: if you want to modify this member function to take an input
00369     // vector x of arbitary sign, change this line below to 
00370     // fracPart = modf(fabs(x[i]),&intPart);
00371     fracPart = modf(x[i],&intPart);
00372 
00373     // if the fractional part is close enough to 0 or 1, we're done with this
00374     // value
00375     while(!(fracPart < dataTol || 1-fracPart < dataTol )) {
00376        // otherwise, multiply by 10 and look at the fractional part of the
00377        // result. 
00378        ++power;
00379        fracPart = fracPart*10.0;
00380        fracPart = modf(fracPart,&intPart);     
00381     }
00382 #else
00383     // use fabs as safer and does no harm
00384     double value = fabs(x[i]);
00385     double scaledValue;
00386     // Do loop - always using original value to stop round off error.
00387     // If we don't find in 15 goes give up
00388     for (power=0;power<16;power++) {
00389       double tolerance = dataTol*multiplier[power];
00390       scaledValue = value*multiplier[power];
00391       fracPart = scaledValue-floor(scaledValue);
00392       if(fracPart < tolerance || 1.0-fracPart < tolerance ) {
00393         break;
00394       }
00395     }
00396     if (power==16||scaledValue>2147483647) {
00397 #ifdef CGL_DEBUG
00398       printf("Overflow %g => %g, power %d\n",x[i],scaledValue,power);
00399 #endif
00400       return -1;
00401     }
00402 #endif    
00403 #ifdef CGL_DEBUG
00404     printf("The smallest power of 10 to make %g  integral = %i\n",x[i],power);
00405 #endif
00406 
00407     
00408     // keep track of the largest power needed so that at the end of the for
00409     // loop
00410     // x[i]*10**maxPower will be integral for all i
00411     if (maxPower < power) maxPower=power;
00412   }
00413 
00414   return maxPower;
00415 }
00416 
00417 //-------------------------------------------------------------------
00418 // Default Constructor 
00419 //-------------------------------------------------------------------
00420 CglSimpleRounding::CglSimpleRounding ()
00421 :
00422 CglCutGenerator(),
00423 epsilon_(1.0e-08)
00424 {
00425   // nothing to do here
00426 }
00427 //-------------------------------------------------------------------
00428 // Copy constructor 
00429 //-------------------------------------------------------------------
00430 CglSimpleRounding::CglSimpleRounding (
00431                   const CglSimpleRounding & source)
00432 :
00433 CglCutGenerator(source),
00434 epsilon_(source.epsilon_)
00435 {  
00436   // Nothing to do here
00437 }
00438 
00439 
00440 //-------------------------------------------------------------------
00441 // Destructor 
00442 //-------------------------------------------------------------------
00443 CglSimpleRounding::~CglSimpleRounding ()
00444 {
00445   // Nothing to do here
00446 }
00447 
00448 //----------------------------------------------------------------
00449 // Assignment operator 
00450 //-------------------------------------------------------------------
00451 CglSimpleRounding &
00452 CglSimpleRounding::operator=(
00453                    const CglSimpleRounding& rhs)
00454 {
00455   if (this != &rhs) {
00456     CglCutGenerator::operator=(rhs);
00457     epsilon_=rhs.epsilon_;
00458   }
00459   return *this;
00460 }

Generated on Wed Dec 3 14:34:56 2003 for Cgl by doxygen 1.3.5