/* 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; }
//-------------------------------------------------------------------------- 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. ); } }
/* 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); }
/* Saves any weights round factorization as pivot rows may change 1) before factorization 2) after factorization 3) just redo infeasibilities 4) restore weights */ void ClpDualRowSteepest::saveWeights(ClpSimplex * model, int mode) { // alternateWeights_ is defined as indexed but is treated oddly model_ = model; int numberRows = model_->numberRows(); int numberColumns = model_->numberColumns(); const int * pivotVariable = model_->pivotVariable(); int i; if (mode == 1) { if(weights_) { // Check if size has changed if (infeasible_->capacity() == numberRows) { alternateWeights_->clear(); // change from row numbers to sequence numbers int * which = alternateWeights_->getIndices(); for (i = 0; i < numberRows; i++) { int iPivot = pivotVariable[i]; which[i] = iPivot; } state_ = 1; } else { // size has changed - clear everything delete [] weights_; weights_ = NULL; delete [] dubiousWeights_; dubiousWeights_ = NULL; delete infeasible_; infeasible_ = NULL; delete alternateWeights_; alternateWeights_ = NULL; delete savedWeights_; savedWeights_ = NULL; state_ = -1; } } } else if (mode == 2 || mode == 4 || mode >= 5) { // restore if (!weights_ || state_ == -1 || mode == 5) { // initialize weights delete [] weights_; delete alternateWeights_; weights_ = new double[numberRows]; alternateWeights_ = new CoinIndexedVector(); // enough space so can use it for factorization alternateWeights_->reserve(numberRows + model_->factorization()->maximumPivots()); if (mode_ != 1 || mode == 5) { // initialize to 1.0 (can we do better?) for (i = 0; i < numberRows; i++) { weights_[i] = 1.0; } } else { CoinIndexedVector * temp = new CoinIndexedVector(); temp->reserve(numberRows + model_->factorization()->maximumPivots()); double * array = alternateWeights_->denseVector(); int * which = alternateWeights_->getIndices(); for (i = 0; i < numberRows; i++) { double value = 0.0; array[0] = 1.0; which[0] = i; alternateWeights_->setNumElements(1); alternateWeights_->setPackedMode(true); model_->factorization()->updateColumnTranspose(temp, alternateWeights_); int number = alternateWeights_->getNumElements(); int j; for (j = 0; j < number; j++) { value += array[j] * array[j]; array[j] = 0.0; } alternateWeights_->setNumElements(0); weights_[i] = value; } delete temp; } // create saved weights (not really indexedvector) savedWeights_ = new CoinIndexedVector(); savedWeights_->reserve(numberRows); double * array = savedWeights_->denseVector(); int * which = savedWeights_->getIndices(); for (i = 0; i < numberRows; i++) { array[i] = weights_[i]; which[i] = pivotVariable[i]; } } else if (mode != 6) { int * which = alternateWeights_->getIndices(); CoinIndexedVector * rowArray3 = model_->rowArray(3); rowArray3->clear(); int * back = rowArray3->getIndices(); // In case something went wrong for (i = 0; i < numberRows + numberColumns; i++) back[i] = -1; if (mode != 4) { // save CoinMemcpyN(which, numberRows, savedWeights_->getIndices()); CoinMemcpyN(weights_, numberRows, savedWeights_->denseVector()); } else { // restore //memcpy(which,savedWeights_->getIndices(), // numberRows*sizeof(int)); //memcpy(weights_,savedWeights_->denseVector(), // numberRows*sizeof(double)); which = savedWeights_->getIndices(); } // restore (a bit slow - but only every re-factorization) double * array = savedWeights_->denseVector(); for (i = 0; i < numberRows; i++) { int iSeq = which[i]; back[iSeq] = i; } for (i = 0; i < numberRows; i++) { int iPivot = pivotVariable[i]; iPivot = back[iPivot]; if (iPivot >= 0) { weights_[i] = array[iPivot]; if (weights_[i] < DEVEX_TRY_NORM) weights_[i] = DEVEX_TRY_NORM; // may need to check more } else { // odd weights_[i] = 1.0; } } } else { // mode 6 - scale back weights as primal errors double primalError = model_->largestPrimalError(); double allowed ; if (primalError > 1.0e3) allowed = 10.0; else if (primalError > 1.0e2) allowed = 50.0; else if (primalError > 1.0e1) allowed = 100.0; else allowed = 1000.0; double allowedInv = 1.0 / allowed; for (i = 0; i < numberRows; i++) { double value = weights_[i]; if (value < allowedInv) value = allowedInv; else if (value > allowed) value = allowed; weights_[i] = allowed; } } state_ = 0; // set up infeasibilities if (!infeasible_) { infeasible_ = new CoinIndexedVector(); infeasible_->reserve(numberRows); } } if (mode >= 2) { // Get dubious weights //if (!dubiousWeights_) //dubiousWeights_=new int[numberRows]; //model_->factorization()->getWeights(dubiousWeights_); infeasible_->clear(); int iRow; const int * pivotVariable = model_->pivotVariable(); double tolerance = model_->currentPrimalTolerance(); for (iRow = 0; iRow < numberRows; iRow++) { int iPivot = pivotVariable[iRow]; double value = model_->solution(iPivot); double lower = model_->lower(iPivot); double upper = model_->upper(iPivot); if (value < lower - tolerance) { value -= lower; value *= value; #ifdef CLP_DUAL_COLUMN_MULTIPLIER if (iPivot < numberColumns) value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns #endif #ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER if (lower == upper) value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables #endif // store square in list infeasible_->quickAdd(iRow, value); } else if (value > upper + tolerance) { value -= upper; value *= value; #ifdef CLP_DUAL_COLUMN_MULTIPLIER if (iPivot < numberColumns) value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns #endif #ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER if (lower == upper) value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables #endif // store square in list infeasible_->quickAdd(iRow, value); } } } }
/* Updates weights and returns pivot alpha. Also does FT update */ double ClpDualRowSteepest::updateWeights(CoinIndexedVector * input, CoinIndexedVector * spare, CoinIndexedVector * spare2, CoinIndexedVector * updatedColumn) { //#define CLP_DEBUG 3 #if CLP_DEBUG>2 // Very expensive debug { int numberRows = model_->numberRows(); CoinIndexedVector * temp = new CoinIndexedVector(); temp->reserve(numberRows + model_->factorization()->maximumPivots()); double * array = alternateWeights_->denseVector(); int * which = alternateWeights_->getIndices(); alternateWeights_->clear(); int i; for (i = 0; i < numberRows; i++) { double value = 0.0; array[i] = 1.0; which[0] = i; alternateWeights_->setNumElements(1); model_->factorization()->updateColumnTranspose(temp, alternateWeights_); int number = alternateWeights_->getNumElements(); int j; for (j = 0; j < number; j++) { int iRow = which[j]; value += array[iRow] * array[iRow]; array[iRow] = 0.0; } alternateWeights_->setNumElements(0); double w = CoinMax(weights_[i], value) * .1; if (fabs(weights_[i] - value) > w) { printf("%d old %g, true %g\n", i, weights_[i], value); weights_[i] = value; // to reduce printout } //else //printf("%d matches %g\n",i,value); } delete temp; } #endif assert (input->packedMode()); if (!updatedColumn->packedMode()) { // I think this means empty #ifdef COIN_DEVELOP printf("updatedColumn not packed mode ClpDualRowSteepest::updateWeights\n"); #endif return 0.0; } double alpha = 0.0; if (!model_->factorization()->networkBasis()) { // clear other region alternateWeights_->clear(); double norm = 0.0; int i; double * work = input->denseVector(); int numberNonZero = input->getNumElements(); int * which = input->getIndices(); double * work2 = spare->denseVector(); int * which2 = spare->getIndices(); // ftran //permute and move indices into index array //also compute norm //int *regionIndex = alternateWeights_->getIndices ( ); const int *permute = model_->factorization()->permute(); //double * region = alternateWeights_->denseVector(); if (permute) { for ( i = 0; i < numberNonZero; i ++ ) { int iRow = which[i]; double value = work[i]; norm += value * value; iRow = permute[iRow]; work2[iRow] = value; which2[i] = iRow; } } else { for ( i = 0; i < numberNonZero; i ++ ) { int iRow = which[i]; double value = work[i]; norm += value * value; //iRow = permute[iRow]; work2[iRow] = value; which2[i] = iRow; } } spare->setNumElements ( numberNonZero ); // Do FT update #if 0 ft_count_in += updatedColumn->getNumElements(); up_count_in += spare->getNumElements(); #endif if (permute || true) { #if CLP_DEBUG>2 printf("REGION before %d els\n", spare->getNumElements()); spare->print(); #endif model_->factorization()->updateTwoColumnsFT(spare2, updatedColumn, spare, permute != NULL); #if CLP_DEBUG>2 printf("REGION after %d els\n", spare->getNumElements()); spare->print(); #endif } else { // Leave as old way model_->factorization()->updateColumnFT(spare2, updatedColumn); model_->factorization()->updateColumn(spare2, spare, false); } #undef CLP_DEBUG #if 0 ft_count += updatedColumn->getNumElements(); up_count += spare->getNumElements(); xx_count++; if ((xx_count % 1000) == 0) printf("zz %d ft %g up %g (in %g %g)\n", xx_count, ft_count, up_count, ft_count_in, up_count_in); #endif numberNonZero = spare->getNumElements(); // alternateWeights_ should still be empty int pivotRow = model_->pivotRow(); #ifdef CLP_DEBUG if ( model_->logLevel ( ) > 4 && fabs(norm - weights_[pivotRow]) > 1.0e-3 * (1.0 + norm)) printf("on row %d, true weight %g, old %g\n", pivotRow, sqrt(norm), sqrt(weights_[pivotRow])); #endif // could re-initialize here (could be expensive) norm /= model_->alpha() * model_->alpha(); assert(model_->alpha()); assert(norm); // pivot element alpha = 0.0; double multiplier = 2.0 / model_->alpha(); // look at updated column work = updatedColumn->denseVector(); numberNonZero = updatedColumn->getNumElements(); which = updatedColumn->getIndices(); int nSave = 0; double * work3 = alternateWeights_->denseVector(); int * which3 = alternateWeights_->getIndices(); const int * pivotColumn = model_->factorization()->pivotColumn(); for (i = 0; i < numberNonZero; i++) { int iRow = which[i]; double theta = work[i]; if (iRow == pivotRow) alpha = theta; double devex = weights_[iRow]; work3[nSave] = devex; // save old which3[nSave++] = iRow; // transform to match spare int jRow = permute ? pivotColumn[iRow] : iRow; double value = work2[jRow]; devex += theta * (theta * norm + value * multiplier); if (devex < DEVEX_TRY_NORM) devex = DEVEX_TRY_NORM; weights_[iRow] = devex; } alternateWeights_->setPackedMode(true); alternateWeights_->setNumElements(nSave); if (norm < DEVEX_TRY_NORM) norm = DEVEX_TRY_NORM; // Try this to make less likely will happen again and stop cycling //norm *= 1.02; weights_[pivotRow] = norm; spare->clear(); #ifdef CLP_DEBUG spare->checkClear(); #endif } else { // Do FT update model_->factorization()->updateColumnFT(spare, updatedColumn); // clear other region alternateWeights_->clear(); double norm = 0.0; int i; double * work = input->denseVector(); int number = input->getNumElements(); int * which = input->getIndices(); double * work2 = spare->denseVector(); int * which2 = spare->getIndices(); for (i = 0; i < number; i++) { int iRow = which[i]; double value = work[i]; norm += value * value; work2[iRow] = value; which2[i] = iRow; } spare->setNumElements(number); // ftran #ifndef NDEBUG alternateWeights_->checkClear(); #endif model_->factorization()->updateColumn(alternateWeights_, spare); // alternateWeights_ should still be empty #ifndef NDEBUG alternateWeights_->checkClear(); #endif int pivotRow = model_->pivotRow(); #ifdef CLP_DEBUG if ( model_->logLevel ( ) > 4 && fabs(norm - weights_[pivotRow]) > 1.0e-3 * (1.0 + norm)) printf("on row %d, true weight %g, old %g\n", pivotRow, sqrt(norm), sqrt(weights_[pivotRow])); #endif // could re-initialize here (could be expensive) norm /= model_->alpha() * model_->alpha(); assert(norm); //if (norm < DEVEX_TRY_NORM) //norm = DEVEX_TRY_NORM; // pivot element alpha = 0.0; double multiplier = 2.0 / model_->alpha(); // look at updated column work = updatedColumn->denseVector(); number = updatedColumn->getNumElements(); which = updatedColumn->getIndices(); int nSave = 0; double * work3 = alternateWeights_->denseVector(); int * which3 = alternateWeights_->getIndices(); for (i = 0; i < number; i++) { int iRow = which[i]; double theta = work[i]; if (iRow == pivotRow) alpha = theta; double devex = weights_[iRow]; work3[nSave] = devex; // save old which3[nSave++] = iRow; double value = work2[iRow]; devex += theta * (theta * norm + value * multiplier); if (devex < DEVEX_TRY_NORM) devex = DEVEX_TRY_NORM; weights_[iRow] = devex; } if (!alpha) { // error - but carry on alpha = 1.0e-50; } alternateWeights_->setPackedMode(true); alternateWeights_->setNumElements(nSave); if (norm < DEVEX_TRY_NORM) norm = DEVEX_TRY_NORM; weights_[pivotRow] = norm; spare->clear(); } #ifdef CLP_DEBUG spare->checkClear(); #endif return alpha; }
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 */