예제 #1
0
/* Returns reduced gradient.Returns an offset (to be added to current one).
 */
double
ClpLinearObjective::reducedGradient(ClpSimplex * model, double * region,
                                    bool /*useFeasibleCosts*/)
{
     int numberRows = model->numberRows();
     //work space
     CoinIndexedVector  * workSpace = model->rowArray(0);

     CoinIndexedVector arrayVector;
     arrayVector.reserve(numberRows + 1);

     int iRow;
#ifdef CLP_DEBUG
     workSpace->checkClear();
#endif
     double * array = arrayVector.denseVector();
     int * index = arrayVector.getIndices();
     int number = 0;
     const double * cost = model->costRegion();
     //assert (!useFeasibleCosts);
     const int * pivotVariable = model->pivotVariable();
     for (iRow = 0; iRow < numberRows; iRow++) {
          int iPivot = pivotVariable[iRow];
          double value = cost[iPivot];
          if (value) {
               array[iRow] = value;
               index[number++] = iRow;
          }
     }
     arrayVector.setNumElements(number);

     int numberColumns = model->numberColumns();

     // Btran basic costs
     double * work = workSpace->denseVector();
     model->factorization()->updateColumnTranspose(workSpace, &arrayVector);
     ClpFillN(work, numberRows, 0.0);
     // now look at dual solution
     double * rowReducedCost = region + numberColumns;
     double * dual = rowReducedCost;
     double * rowCost = model->costRegion(0);
     for (iRow = 0; iRow < numberRows; iRow++) {
          dual[iRow] = array[iRow];
     }
     double * dj = region;
     ClpDisjointCopyN(model->costRegion(1), numberColumns, dj);
     model->transposeTimes(-1.0, dual, dj);
     for (iRow = 0; iRow < numberRows; iRow++) {
          // slack
          double value = dual[iRow];
          value += rowCost[iRow];
          rowReducedCost[iRow] = value;
     }
     return 0.0;
}
예제 #2
0
/* Return <code>x *A</code> in <code>z</code> but
   just for number indices in y.
   Default cheats with fake CoinIndexedVector and
   then calls subsetTransposeTimes */
void
ClpMatrixBase::listTransposeTimes(const ClpSimplex * model,
                                  double * x,
                                  int * y,
                                  int number,
                                  double * z) const
{
     CoinIndexedVector pi;
     CoinIndexedVector list;
     CoinIndexedVector output;
     int * saveIndices = list.getIndices();
     list.setNumElements(number);
     list.setIndexVector(y);
     double * savePi = pi.denseVector();
     pi.setDenseVector(x);
     double * saveOutput = output.denseVector();
     output.setDenseVector(z);
     output.setPacked();
     subsetTransposeTimes(model, &pi, &list, &output);
     // restore settings
     list.setIndexVector(saveIndices);
     pi.setDenseVector(savePi);
     output.setDenseVector(saveOutput);
}
예제 #3
0
//--------------------------------------------------------------------------
void
CoinIndexedVectorUnitTest()
{
  
  int i;
  // Test default constructor
  {
    CoinIndexedVector r;
    assert( r.indices_==NULL );
    assert( r.elements_==NULL );
    assert( r.getNumElements()==0 );
    assert( r.capacity_==0);
  }
  
  // Test set and get methods
  const int ne = 4;
  int inx[ne] = { 1, 3, 4, 7 };
  double el[ne] = { 1.2, 3.4, 5.6, 7.8 };
  {
    CoinIndexedVector r;    
    assert( r.getNumElements()==0 );
    
    // Test setting/getting elements with int* & float* vectors
    r.setVector( ne, inx, el );
    assert( r.getNumElements()==ne );
    for ( i=0; i<ne; i++ ) {
      assert( r.getIndices()[i]  == inx[i] );
      assert( r[inx[i]]  == el[i] );
    }
    
    // Test setting/getting elements with indices out of order  
    const int ne2 = 5;
    int inx2[ne2] = { 2, 4, 8, 14, 3 };
    double el2[ne2] = { 2.2, 4.4, 6.6, 8.8, 3.3 };
    
    r.setVector(ne2,inx2,el2);
    
    assert( r.getNumElements()==ne2 );    
    
    assert( r.getIndices()[0]==inx2[0] );
    
    assert( r.getIndices()[1]==inx2[1] );
    
    assert( r.getIndices()[2]==inx2[2] );
    
    assert( r.getIndices()[3]==inx2[3] );
    
    assert( r.getIndices()[4]==inx2[4] );
    

    CoinIndexedVector r1(ne2,inx2,el2);
    assert( r == r1 );   
  }    
  CoinIndexedVector r;
  
  
  {
    CoinIndexedVector r;
    const int ne = 3;
    int inx[ne] = { 1, 2, 3 };
    double el[ne] = { 2.2, 4.4, 8.8};
    r.setVector(ne,inx,el);
    int c = r.capacity();
    // Test swap function
    r.swap(0,2);
    assert( r.getIndices()[0]==3 );
    assert( r.getIndices()[1]==2 );
    assert( r.getIndices()[2]==1 );
    assert( r.capacity() == c );
    
    // Test the append function
    CoinIndexedVector s;
    const int nes = 4;
    int inxs[nes] = { 11, 12, 13, 14 };
    double els[nes] = { .122, 14.4, 18.8, 19.9};
    s.setVector(nes,inxs,els);
    r.append(s);
    assert( r.getNumElements()==7 );
    assert( r.getIndices()[0]==3 );
    assert( r.getIndices()[1]==2 );
    assert( r.getIndices()[2]==1 );
    assert( r.getIndices()[3]==11 );
    assert( r.getIndices()[4]==12 );
    assert( r.getIndices()[5]==13 );
    assert( r.getIndices()[6]==14 );
    
    // Test the resize function
    c = r.capacity();
    r.truncate(4);
    // we will lose 11
    assert( r.getNumElements()==3 );
    assert( r.getIndices()[0]==3 );
    assert( r.getIndices()[1]==2 );
    assert( r.getIndices()[2]==1 );
    assert( r.getMaxIndex() == 3 );
    assert( r.getMinIndex() == 1 );
    assert( r.capacity() == c );
  }
  
  // Test borrow and return vector
  {
    CoinIndexedVector r,r2;
    const int ne = 3;
    int inx[ne] = { 1, 2, 3 };
    double el[ne] = { 2.2, 4.4, 8.8};
    double els[4] = { 0.0,2.2, 4.4, 8.8};
    r.setVector(ne,inx,el);
    r2.borrowVector(4,ne,inx,els);
    assert (r==r2);
    r2.returnVector();
    assert (!r2.capacity());
    assert (!r2.getNumElements());
    assert (!r2.denseVector());
    assert (!r2.getIndices());
  }
  
  // Test copy constructor and assignment operator
  {
    CoinIndexedVector rhs;
    {
      CoinIndexedVector r;
      {
	CoinIndexedVector rC1(r);      
	assert( 0==r.getNumElements() );
	assert( 0==rC1.getNumElements() );
	
	
	r.setVector( ne, inx, el ); 
	
	assert( ne==r.getNumElements() );
	assert( 0==rC1.getNumElements() ); 
      }
      
      CoinIndexedVector rC2(r);   
      
      assert( ne==r.getNumElements() );
      assert( ne==rC2.getNumElements() );
      
      for ( i=0; i<ne; i++ ) {
	assert( r.getIndices()[i] == rC2.getIndices()[i] );
      }
      
      rhs=rC2;
    }
    // Test that rhs has correct values even though lhs has gone out of scope
    assert( rhs.getNumElements()==ne );
    
    for ( i=0; i<ne; i++ ) {
      assert( inx[i] == rhs.getIndices()[i] );
    } 
  }
  
  // Test operator==
  {
    CoinIndexedVector v1,v2;
    assert( v1==v2 );
    assert( v2==v1 );
    assert( v1==v1 );
    assert( !(v1!=v2) );
    
    v1.setVector( ne, inx, el );
    assert ( !(v1==v2) );
    assert ( v1!=v2 );
    
    CoinIndexedVector v3(v1);
    assert( v3==v1 );
    assert( v3!=v2 );
    
    CoinIndexedVector v4(v2);
    assert( v4!=v1 );
    assert( v4==v2 );
  }
  
  {
    // Test sorting of indexed vectors    
    const int ne = 4;
    int inx[ne] = { 1, 4, 0, 2 };
    double el[ne] = { 10., 40., 1., 20. };
    CoinIndexedVector r;
    r.setVector(ne,inx,el);
    
    // Test that indices are in increasing order
    r.sort();
    for ( i=1; i<ne; i++ ) assert( r.getIndices()[i-1] < r.getIndices()[i] );

  }    
  {
    // Test operator[] and indexExists()
    const int ne = 4;
    int inx[ne] =   {  1,   4,  0,   2 };
    double el[ne] = { 10., 40., 1., 50. };
    CoinIndexedVector r;
    bool errorThrown = false;
    try {
      assert( r[1]==0. );
    }
    catch (CoinError& e) {
      errorThrown = true;
    }
    assert( errorThrown );
    
    r.setVector(ne,inx,el);
    
    errorThrown = false;
    try {
      assert( r[-1]==0. );
    }
    catch (CoinError& e) {
      errorThrown = true;
    }
    assert( errorThrown );
    
    assert( r[ 0]==1. );
    assert( r[ 1]==10.);
    assert( r[ 2]==50.);
    assert( r[ 3]==0. );
    assert( r[ 4]==40.);
    errorThrown = false;
    try {
      assert( r[5]==0. );
    }
    catch (CoinError& e) {
      errorThrown = true;
    }
    assert( errorThrown );
    
    assert ( r.getMaxIndex()==4 );
    assert ( r.getMinIndex()==0 );
  }
  
  // Test that attemping to get min/max index of a 0,
  // length vector 
  {
    CoinIndexedVector nullVec;
    assert( nullVec.getMaxIndex() == -COIN_INT_MAX/*0*/ );
    assert( nullVec.getMinIndex() == COIN_INT_MAX/*0*/ );
  } 
  
  // Test CoinFltEq with equivalent method
  {    
    const int ne = 4;
    int inx1[ne] = { 1, 3, 4, 7 };
    double el1[ne] = { 1.2, 3.4, 5.6, 7.8 };
    int inx2[ne] = { 7, 4, 3, 1 };
    double el2[ne] = { 7.8+.5, 5.6+.5, 3.4+.5, 1.2+.5 };
    CoinIndexedVector v1,v2;
    v1.setVector(ne,inx1,el1);
    v2.setVector(ne,inx2,el2);
  }
  
  {
    // Test reserve
    CoinIndexedVector v1,v2;
    assert( v1.capacity()==0 );
    v1.reserve(6);
    assert( v1.capacity()==6 );
    assert( v1.getNumElements()==0 );
    v2=v1;
    assert( v2.capacity() == 6 );
    assert( v2.getNumElements()==0 );
    assert( v2==v1 );
    v1.setVector(0,NULL,NULL);
    assert( v1.capacity()==6 );
    assert( v1.getNumElements()==0 );
    assert( v2==v1 );
    v2=v1;
    assert( v2.capacity() == 6 );
    assert( v2.getNumElements()==0 );
    assert( v2==v1 );
    
    const int ne = 2;
    int inx[ne] = { 1, 3 };
    double el[ne] = { 1.2, 3.4 };
    v1.setVector(ne,inx,el);
    assert( v1.capacity()==6 );
    assert( v1.getNumElements()==2 );
    v2=v1;
    assert( v2.capacity()==6 );
    assert( v2.getNumElements()==2 );
    assert( v2==v1 );
    
    const int ne1 = 5;
    int inx1[ne1] = { 1, 3, 4, 5, 6 };
    double el1[ne1] = { 1.2, 3.4, 5., 6., 7. };
    v1.setVector(ne1,inx1,el1);
    assert( v1.capacity()==7 );
    assert( v1.getNumElements()==5 );
    v2=v1;
    assert( v2.capacity()==7 );
    assert( v2.getNumElements()==5 );
    assert( v2==v1 );
    
    const int ne2 = 8;
    int inx2[ne2] = { 1, 3, 4, 5, 6, 7, 8, 9 };
    double el2[ne2] = { 1.2, 3.4, 5., 6., 7., 8., 9., 10. };
    v1.setVector(ne2,inx2,el2);
    assert( v1.capacity()==10 );
    assert( v1.getNumElements()==8 );
    v2=v1;
    assert( v2.getNumElements()==8 );    
    assert( v2==v1 );
    
    v1.setVector(ne1,inx1,el1);
    assert( v1.capacity()==10 );
    assert( v1.getNumElements()==5 );
    v2=v1;    
    assert( v2.capacity()==10 );
    assert( v2.getNumElements()==5 );
    assert( v2==v1 );
    
    v1.reserve(7);
    assert( v1.capacity()==10 );
    assert( v1.getNumElements()==5 );
    v2=v1;
    assert( v2.capacity()==10 );
    assert( v2.getNumElements()==5 );
    assert( v2==v1 );
    
  }
  
  // Test the insert method
  {
    CoinIndexedVector v1;
    assert( v1.getNumElements()==0 );
    assert( v1.capacity()==0 );
    
    v1.insert(1,1.);
    assert( v1.getNumElements()==1 );
    assert( v1.capacity()==2 );
    assert( v1.getIndices()[0] == 1 );
    
    v1.insert(10,10.);
    assert( v1.getNumElements()==2 );
    assert( v1.capacity()==11 );
    assert( v1.getIndices()[1] == 10 );
    
    v1.insert(20,20.);
    assert( v1.getNumElements()==3 );
    assert( v1.capacity()==21 );
    assert( v1.getIndices()[2] == 20 );
    
    v1.insert(30,30.);
    assert( v1.getNumElements()==4 );
    assert( v1.capacity()==31 );
    assert( v1.getIndices()[3] == 30 );

    v1.insert(40,40.);
    assert( v1.getNumElements()==5 );
    assert( v1.capacity()==41 );
    assert( v1.getIndices()[4] == 40 );
    
    v1.insert(50,50.);
    assert( v1.getNumElements()==6 );
    assert( v1.capacity()==51 );
    assert( v1.getIndices()[5] == 50 );
    
    CoinIndexedVector v2;
    const int ne1 = 3;
    int inx1[ne1] = { 1, 3, 4 };
    double el1[ne1] = { 1.2, 3.4, 5. };
    v2.setVector(ne1,inx1,el1);    
    assert( v2.getNumElements()==3 );
    assert( v2.capacity()==5 );

    // Test clean method - get rid of 1.2
    assert(v2.clean(3.0)==2);
    assert(v2.denseVector()[1]==0.0);

    // Below are purely for debug - so use assert
    // so we won't try with false
    // Test checkClean 
#ifndef NO_CHECK_CL
    v2.checkClean();
    assert( v2.getNumElements()==2 );

    // Get rid of all
    int numberRemaining = v2.clean(10.0);
    assert(numberRemaining==0);
    v2.checkClear();
#endif    
  }
  
  {
    //Test setConstant and setElement     
    CoinIndexedVector v2;
    const int ne1 = 3;
    int inx1[ne1] = { 1, 3, 4 };
    v2.setConstant(ne1,inx1,3.14);    
    assert( v2.getNumElements()==3 );
    assert( v2.capacity()==5 );
    assert( v2.getIndices()[0]==1 );
    assert( v2.getIndices()[1]==3 );
    assert( v2.getIndices()[2]==4 );
    
    assert( v2[3] == 3.14 );
    
    CoinIndexedVector v2X(ne1,inx1,3.14);
    assert( v2 == v2X );
    
  }
  
  {
    //Test setFull 
    CoinIndexedVector v2;
    const int ne2 = 3;
    double el2[ne2] = { 1., 3., 4. };
    v2.setFull(ne2,el2);    
    assert( v2.getNumElements()==3 );
    assert( v2.capacity()==3 );
    assert( v2.getIndices()[0]==0 );
    assert( v2.getIndices()[1]==1 );
    assert( v2.getIndices()[2]==2 );
    
    assert( v2[1] == 3. );
    
    CoinIndexedVector v2X(ne2,el2);
    assert( v2 == v2X ); 
    
    v2.setFull(0,el2); 
    assert( v2[2] == 0. );  
  }
  
  
#if 0
  // what happens when someone sets 
  // the number of elements to be a negative number
  {    
    const int ne = 4;
    int inx1[ne] = { 1, 3, 4, 7 };
    double el1[ne] = { 1.2, 3.4, 5.6, 7.8 };
    CoinIndexedVector v1;
    v1.set(-ne,inx1,el1);
  }
#endif
  
  
  // Test copy constructor from ShallowPackedVector
  {
    const int ne = 4;
    int inx[ne] =   {  1,   4,  0,   2 };
    double el[ne] = { 10., 40., 1., 50. };
    CoinIndexedVector std(ne,inx,el);
    CoinShallowPackedVector * spvP = new CoinShallowPackedVector(ne,inx,el);
    CoinIndexedVector pv(*spvP);
    assert( pv == std );
    delete spvP;
    assert( pv == std );
  }
  
  // Test assignment from ShallowPackedVector
  {
    const int ne = 4;
    int inx[ne] =   {  1,   4,  0,   2 };
    double el[ne] = { 10., 40., 1., 50. };
    CoinIndexedVector std(ne,inx,el);
    CoinShallowPackedVector * spvP = new CoinShallowPackedVector(ne,inx,el);
    CoinIndexedVector pv;
    pv = *spvP;
    assert( pv == std );
    delete spvP;
    assert( pv == std );
  }
  
  {
    // Test that sample usage works
    
    const int ne = 4;
    int inx[ne] =   {  1,   4,  0,   2 };
    double el[ne] = { 10., 40., 1., 50. };
    CoinIndexedVector r(ne,inx,el);
    
    assert( r.getIndices()[0]== 1  );
    assert( r.getIndices()[1]== 4  );
    assert( r.getIndices()[2]== 0  );
    assert( r.getIndices()[3]== 2  );
    
    assert( r[ 0]==1. );
    assert( r[ 1]==10.);
    assert( r[ 2]==50.);
    assert( r[ 3]==0. );
    assert( r[ 4]==40.);
    
    r.sortIncrElement();
    
    assert( r.getIndices()[0]== 0  );
    assert( r.getIndices()[1]== 1  );
    assert( r.getIndices()[2]== 4  );
    assert( r.getIndices()[3]== 2  );
    
    assert( r[ 0]==1. );
    assert( r[ 1]==10.);
    assert( r[ 2]==50.);
    assert( r[ 3]==0. );
    assert( r[ 4]==40.);
    
    CoinIndexedVector r1;
    r1=r;
    assert( r==r1 );
    
    CoinIndexedVector add = r + r1;
    assert( add[0] ==  1.+ 1. );
    assert( add[1] == 10.+10. );
    assert( add[2] == 50.+50. );
    assert( add[3] ==  0.+ 0. );
    assert( add[4] == 40.+40. );
    
  }
  
}
예제 #4
0
void CglGMI::generateCuts(OsiCuts &cs)
{
  isInteger = new bool[ncol]; 
  
  computeIsInteger();

  cstat = new int[ncol];
  rstat = new int[nrow];


  solver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
                                          // 2: upper 3: lower


#if defined GMI_TRACETAB
  printvecINT("cstat", cstat, ncol);
  printvecINT("rstat", rstat, nrow);
#endif

  // list of basic integer fractional variables
  int *listFracBasic = new int[nrow];
  int numFracBasic = 0;
  for (int i = 0; i < ncol; ++i) {
    // j is the variable which is basic in row i
    if ((cstat[i] == 1) && (isInteger[i])) {
      if (CoinMin(aboveInteger(xlp[i]),
		  1-aboveInteger(xlp[i])) > param.getAway()) {
	listFracBasic[numFracBasic] = i;
	numFracBasic++;
      }
#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
      else if (trackRejection) {	
	// Say that we tried to generate a cut, but it was discarded
	// because of small fractionality
	if (!isIntegerValue(xlp[i])) {
	  fracFail++;
	  numGeneratedCuts++;
	}
      }
#endif
    }
  }

#if defined GMI_TRACE
  printf("CglGMI::generateCuts() : %d fractional rows\n", numFracBasic);
#endif
  
  if (numFracBasic == 0) {
    delete[] listFracBasic;
    delete[] cstat;
    delete[] rstat;
    delete[] isInteger;
    return;
  }

  // there are rows with basic integer fractional variables, so we can
  // generate cuts

  // Basis index for columns and rows; each element is -1 if corresponding
  // variable is nonbasic, and contains the basis index if basic.
  // The basis index is the row in which the variable is basic.
  int* colBasisIndex = new int[ncol];
  int* rowBasisIndex = new int[nrow];

#if defined OSI_TABLEAU
  memset(colBasisIndex, -1, ncol*sizeof(int));
  memset(rowBasisIndex, -1, nrow*sizeof(int));
  solver->enableFactorization();
  int* basicVars = new int[nrow];
  solver->getBasics(basicVars);
  for (int i = 0; i < nrow; ++i) {
    if (basicVars[i] < ncol) {
      colBasisIndex[basicVars[i]] = i;
    }
    else {
      rowBasisIndex[basicVars[i] - ncol] = i;
    }
  }
#else
  CoinFactorization factorization;
  if (factorize(factorization, colBasisIndex, rowBasisIndex)) {
    printf("### WARNING: CglGMI::generateCuts(): error during factorization!\n");
    return;
  }
#endif


  // cut in sparse form
  double* cutElem = new double[ncol];
  int* cutIndex = new int[ncol];
  int cutNz = 0;
  double cutRhs;

  // cut in dense form
  double* cut = new double[ncol];

  double *slackVal = new double[nrow];

  for (int i = 0; i < nrow; ++i) {
    slackVal[i] = rowRhs[i] - rowActivity[i];
  }

#if defined OSI_TABLEAU
  // Column part and row part of a row of the simplex tableau
  double* tableauColPart = new double[ncol];
  double* tableauRowPart = new double[nrow];
#else
  // Need some more data for simplex tableau computation
  const int * row = byCol->getIndices();
  const CoinBigIndex * columnStart = byCol->getVectorStarts();
  const int * columnLength = byCol->getVectorLengths(); 
  const double * columnElements = byCol->getElements();

  // Create work arrays for factorization
  // two vectors for updating: the first one is needed to do the computations
  // but we do not use it, the second one contains a row of the basis inverse
  CoinIndexedVector work;
  CoinIndexedVector array;
  // Make sure they large enough
  work.reserve(nrow);
  array.reserve(nrow);
  int * arrayRows = array.getIndices();
  double * arrayElements = array.denseVector();
  // End of code to create work arrays
  double one = 1.0;
#endif

  // Matrix elements by row for slack substitution
  const double *elements = byRow->getElements();
  const int *rowStart = byRow->getVectorStarts();
  const int *indices = byRow->getIndices();
  const int *rowLength = byRow->getVectorLengths(); 

  // Indices of basic and slack variables, and cut elements
  int iBasic, slackIndex;
  double cutCoeff;
  double rowElem;
  // Now generate the cuts: obtain a row of the simplex tableau
  // where an integer variable is basic and fractional, and compute the cut
  for (int i = 0; i < numFracBasic; ++i) {
    if (!computeCutFractionality(xlp[listFracBasic[i]], cutRhs)) {
      // cut is discarded because of the small fractionalities involved
#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
      if (trackRejection) {	
	// Say that we tried to generate a cut, but it was discarded
	// because of small fractionality
	fracFail++;
	numGeneratedCuts++;
      }
#endif
      continue;
    }

    // the variable listFracBasic[i] is basic in row iBasic
    iBasic = colBasisIndex[listFracBasic[i]];

#if defined GMI_TRACE
    printf("Row %d with var %d basic, f0 = %f\n", i, listFracBasic[i], f0);
#endif

#if defined OSI_TABLEAU
    solver->getBInvARow(iBasic, tableauColPart, tableauRowPart);
#else
    array.clear();
    array.setVector(1, &iBasic, &one);

    factorization.updateColumnTranspose (&work, &array);

    int numberInArray=array.getNumElements();
#endif

    // reset the cut
    memset(cut, 0, ncol*sizeof(double));

    // columns
    for (int j = 0; j < ncol; ++j) {
      if ((colBasisIndex[j] >= 0) || 
	  (areEqual(colLower[j], colUpper[j], 
		    param.getEPS(), param.getEPS()))) {
	// Basic or fixed variable -- skip
	continue;
      }
#ifdef OSI_TABLEAU
      rowElem = tableauColPart[j];
#else
      rowElem = 0.0;
      // add in row of tableau
      for (int h = columnStart[j]; h < columnStart[j]+columnLength[j]; ++h) {
	rowElem += columnElements[h]*arrayElements[row[h]];
      }
#endif
      if (!isZero(fabs(rowElem))) {
	// compute cut coefficient
	flip(rowElem, j);
	cutCoeff = computeCutCoefficient(rowElem, j);
	if (isZero(cutCoeff)) {
	  continue;
	}
	unflipOrig(cutCoeff, j, cutRhs);
	cut[j] = cutCoeff;
#if defined GMI_TRACE
	printf("var %d, row %f, cut %f\n", j, rowElem, cutCoeff);
#endif
      }
    }

    // now do slacks part
#if defined OSI_TABLEAU
    for (int j = 0 ; j < nrow; ++j) {
      // index of the row corresponding to the slack variable
      slackIndex = j;
      if (rowBasisIndex[j] >= 0) {
	// Basic variable -- skip it
	continue;
      }
      rowElem = tableauRowPart[j];
#else
    for (int j = 0 ; j < numberInArray ; ++j) {
      // index of the row corresponding to the slack variable
      slackIndex = arrayRows[j];
      rowElem = arrayElements[slackIndex];
#endif
      if (!isZero(fabs(rowElem))) {
	slackIndex += ncol;
	// compute cut coefficient
	flip(rowElem, slackIndex);
	cutCoeff = computeCutCoefficient(rowElem, slackIndex);
	if (isZero(fabs(cutCoeff))) {
	  continue;
	}
	unflipSlack(cutCoeff, slackIndex, cutRhs, slackVal);
	eliminateSlack(cutCoeff, slackIndex, cut, cutRhs,
		       elements, rowStart, indices, rowLength, rowRhs);
#if defined GMI_TRACE
	printf("var %d, row %f, cut %f\n", slackIndex, rowElem, cutCoeff);
#endif
      }
    }

    packRow(cut, cutElem, cutIndex, cutNz);
    if (cutNz == 0)
      continue;

#if defined GMI_TRACE
    printvecDBL("final cut:", cutElem, cutIndex, cutNz);
    printf("cutRhs: %f\n", cutRhs);
#endif
    
#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
    if (trackRejection) {
      numGeneratedCuts++;
    }
#endif
    if (cleanCut(cutElem, cutIndex, cutNz, cutRhs, xlp) && cutNz > 0) {
      OsiRowCut rc;
      rc.setRow(cutNz, cutIndex, cutElem);
      rc.setLb(-param.getINFINIT());
      rc.setUb(cutRhs);
      if (!param.getCHECK_DUPLICATES()) {
	cs.insert(rc);
      }
      else{
	cs.insertIfNotDuplicate(rc, CoinAbsFltEq(param.getEPS_COEFF()));
      }
    }

  }

#if defined GMI_TRACE
  printf("CglGMI::generateCuts() : number of cuts : %d\n", cs.sizeRowCuts());
#endif

#if defined OSI_TABLEAU
  solver->disableFactorization();
  delete[] basicVars;
  delete[] tableauColPart;
  delete[] tableauRowPart;
#endif

  delete[] colBasisIndex;
  delete[] rowBasisIndex;
  delete[] cut;
  delete[] slackVal;
  delete[] cutElem;
  delete[] cutIndex;
  delete[] listFracBasic;
  delete[] cstat;
  delete[] rstat;
  delete[] isInteger;

} /* generateCuts */

/***********************************************************************/
void CglGMI::setParam(const CglGMIParam &source) {
  param = source;
} /* setParam */

/***********************************************************************/
void CglGMI::computeIsInteger() {
  for (int i = 0; i < ncol; ++i) {
    if(solver->isInteger(i)) {
      isInteger[i] = true;
    }
    else {
      if((areEqual(colLower[i], colUpper[i], 
		   param.getEPS(), param.getEPS()))
	 && (isIntegerValue(colUpper[i]))) {	
	// continuous variable fixed to an integer value
	isInteger[i] = true;
      }
      else {
	isInteger[i] = false;
      }
    }
  }    
} /* computeIsInteger */

/***********************************************************************/
void CglGMI::printOptTab(OsiSolverInterface *lclSolver) const
{
  int *cstat = new int[ncol];
  int *rstat = new int[nrow];

  lclSolver->enableFactorization();
  lclSolver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
  // 2: upper 3: lower

  int *basisIndex = new int[nrow]; // basisIndex[i] = 
                                    //        index of pivot var in row i
                                    //        (slack if number >= ncol) 
  lclSolver->getBasics(basisIndex);

  double *z = new double[ncol];  // workspace to get row of the tableau
  double *slack = new double[nrow];  // workspace to get row of the tableau
  double *slackVal = new double[nrow];

  for (int i = 0; i < nrow; i++) {
    slackVal[i] = rowRhs[i] - rowActivity[i];
  }

  const double *rc = lclSolver->getReducedCost();
  const double *dual = lclSolver->getRowPrice();
  const double *solution = lclSolver->getColSolution();

  printvecINT("cstat", cstat, ncol);
  printvecINT("rstat", rstat, nrow);
  printvecINT("basisIndex", basisIndex, nrow);

  printvecDBL("solution", solution, ncol);
  printvecDBL("slackVal", slackVal, nrow);
  printvecDBL("reduced_costs", rc, ncol);
  printvecDBL("dual solution", dual, nrow);

  printf("Optimal Tableau:\n");

  for (int i = 0; i < nrow; i++) {
    lclSolver->getBInvARow(i, z, slack);
    for (int ii = 0; ii < ncol; ++ii) {
      printf("%5.2f ", z[ii]);
    }
    printf(" | ");
    for (int ii = 0; ii < nrow; ++ii) {
      printf("%5.2f ", slack[ii]);
    }
    printf(" | ");
    if(basisIndex[i] < ncol) {
      printf("%5.2f ", solution[basisIndex[i]]);
    }
    else {
      printf("%5.2f ", slackVal[basisIndex[i]-ncol]);
    }
    printf("\n");
  }
  for (int ii = 0; ii < 7*(ncol+nrow+1); ++ii) {
    printf("-");
  }
  printf("\n");

  for (int ii = 0; ii < ncol; ++ii) {
    printf("%5.2f ", rc[ii]);    
  }
  printf(" | ");
  for (int ii = 0; ii < nrow; ++ii) {
    printf("%5.2f ", -dual[ii]);
  }
  printf(" | ");
  printf("%5.2f\n", -lclSolver->getObjValue());
  lclSolver->disableFactorization();

  delete[] cstat;
  delete[] rstat;
  delete[] basisIndex;
  delete[] slack;
  delete[] z;
  delete[] slackVal;
} /* printOptTab */