/* $Id$ */ // Copyright (C) 2002, International Business Machines // Corporation and others. All Rights Reserved. // This code is licensed under the terms of the Eclipse Public License (EPL). #include "CoinPragma.hpp" #include "ClpSimplex.hpp" #include "ClpDualRowSteepest.hpp" #include "CoinIndexedVector.hpp" #include "ClpFactorization.hpp" #include "CoinHelperFunctions.hpp" #include //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //#define CLP_DEBUG 4 //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- ClpDualRowSteepest::ClpDualRowSteepest(int mode) : ClpDualRowPivot() , state_(-1) , mode_(mode) , persistence_(normal) , weights_(NULL) , infeasible_(NULL) , alternateWeights_(NULL) , savedWeights_(NULL) , dubiousWeights_(NULL) { type_ = 2 + 64 * mode; } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- ClpDualRowSteepest::ClpDualRowSteepest(const ClpDualRowSteepest &rhs) : ClpDualRowPivot(rhs) { state_ = rhs.state_; mode_ = rhs.mode_; persistence_ = rhs.persistence_; model_ = rhs.model_; if ((model_ && model_->whatsChanged() & 1) != 0) { int number = model_->numberRows(); if (rhs.savedWeights_) number = CoinMin(number, rhs.savedWeights_->capacity()); if (rhs.infeasible_) { infeasible_ = new CoinIndexedVector(rhs.infeasible_); } else { infeasible_ = NULL; } if (rhs.weights_) { weights_ = new double[number]; ClpDisjointCopyN(rhs.weights_, number, weights_); } else { weights_ = NULL; } if (rhs.alternateWeights_) { alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_); } else { alternateWeights_ = NULL; } if (rhs.savedWeights_) { savedWeights_ = new CoinIndexedVector(rhs.savedWeights_); } else { savedWeights_ = NULL; } if (rhs.dubiousWeights_) { assert(model_); int number = model_->numberRows(); dubiousWeights_ = new int[number]; ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_); } else { dubiousWeights_ = NULL; } } else { infeasible_ = NULL; weights_ = NULL; alternateWeights_ = NULL; savedWeights_ = NULL; dubiousWeights_ = NULL; } } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- ClpDualRowSteepest::~ClpDualRowSteepest() { delete[] weights_; delete[] dubiousWeights_; delete infeasible_; delete alternateWeights_; delete savedWeights_; } //---------------------------------------------------------------- // Assignment operator //------------------------------------------------------------------- ClpDualRowSteepest & ClpDualRowSteepest::operator=(const ClpDualRowSteepest &rhs) { if (this != &rhs) { ClpDualRowPivot::operator=(rhs); state_ = rhs.state_; mode_ = rhs.mode_; persistence_ = rhs.persistence_; model_ = rhs.model_; delete[] weights_; delete[] dubiousWeights_; delete infeasible_; delete alternateWeights_; delete savedWeights_; assert(model_); int number = model_->numberRows(); if (rhs.savedWeights_) number = CoinMin(number, rhs.savedWeights_->capacity()); if (rhs.infeasible_ != NULL) { infeasible_ = new CoinIndexedVector(rhs.infeasible_); } else { infeasible_ = NULL; } if (rhs.weights_ != NULL) { weights_ = new double[number]; ClpDisjointCopyN(rhs.weights_, number, weights_); } else { weights_ = NULL; } if (rhs.alternateWeights_ != NULL) { alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_); } else { alternateWeights_ = NULL; } if (rhs.savedWeights_ != NULL) { savedWeights_ = new CoinIndexedVector(rhs.savedWeights_); } else { savedWeights_ = NULL; } if (rhs.dubiousWeights_) { assert(model_); int number = model_->numberRows(); dubiousWeights_ = new int[number]; ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_); } else { dubiousWeights_ = NULL; } } return *this; } // Fill most values void ClpDualRowSteepest::fill(const ClpDualRowSteepest &rhs) { state_ = rhs.state_; mode_ = rhs.mode_; persistence_ = rhs.persistence_; assert(model_->numberRows() == rhs.model_->numberRows()); model_ = rhs.model_; assert(model_); int number = model_->numberRows(); if (rhs.savedWeights_) number = CoinMin(number, rhs.savedWeights_->capacity()); if (rhs.infeasible_ != NULL) { if (!infeasible_) infeasible_ = new CoinIndexedVector(rhs.infeasible_); else *infeasible_ = *rhs.infeasible_; } else { delete infeasible_; infeasible_ = NULL; } if (rhs.weights_ != NULL) { if (!weights_) weights_ = new double[number]; ClpDisjointCopyN(rhs.weights_, number, weights_); } else { delete[] weights_; weights_ = NULL; } if (rhs.alternateWeights_ != NULL) { if (!alternateWeights_) alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_); else *alternateWeights_ = *rhs.alternateWeights_; } else { delete alternateWeights_; alternateWeights_ = NULL; } if (rhs.savedWeights_ != NULL) { if (!savedWeights_) savedWeights_ = new CoinIndexedVector(rhs.savedWeights_); else *savedWeights_ = *rhs.savedWeights_; } else { delete savedWeights_; savedWeights_ = NULL; } if (rhs.dubiousWeights_) { assert(model_); int number = model_->numberRows(); if (!dubiousWeights_) dubiousWeights_ = new int[number]; ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_); } else { delete[] dubiousWeights_; dubiousWeights_ = NULL; } } // Returns pivot row, -1 if none int ClpDualRowSteepest::pivotRow() { assert(model_); int i, iRow; double *infeas = infeasible_->denseVector(); double largest = 0.0; int *index = infeasible_->getIndices(); int number = infeasible_->getNumElements(); const int *pivotVariable = model_->pivotVariable(); int chosenRow = -1; int lastPivotRow = model_->pivotRow(); assert(lastPivotRow < model_->numberRows()); double tolerance = model_->currentPrimalTolerance(); // we can't really trust infeasibilities if there is primal error // this coding has to mimic coding in checkPrimalSolution double error = CoinMin(1.0e-2, model_->largestPrimalError()); // allow tolerance at least slightly bigger than standard tolerance = tolerance + error; // But cap tolerance = CoinMin(1000.0, tolerance); tolerance *= tolerance; // as we are using squares bool toleranceChanged = false; double *solution = model_->solutionRegion(); double *lower = model_->lowerRegion(); double *upper = model_->upperRegion(); // do last pivot row one here //#define CLP_DUAL_FIXED_COLUMN_MULTIPLIER 10.0 if (lastPivotRow >= 0 && lastPivotRow < model_->numberRows()) { #ifdef CLP_DUAL_COLUMN_MULTIPLIER int numberColumns = model_->numberColumns(); #endif int iPivot = pivotVariable[lastPivotRow]; double value = solution[iPivot]; double lower = model_->lower(iPivot); double upper = model_->upper(iPivot); 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 // store square in list if (infeas[lastPivotRow]) infeas[lastPivotRow] = value; // already there else infeasible_->quickAdd(lastPivotRow, value); } else 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 // store square in list if (infeas[lastPivotRow]) infeas[lastPivotRow] = value; // already there else infeasible_->add(lastPivotRow, value); } else { // feasible - was it infeasible - if so set tiny if (infeas[lastPivotRow]) infeas[lastPivotRow] = COIN_INDEXED_REALLY_TINY_ELEMENT; } number = infeasible_->getNumElements(); } if (model_->numberIterations() < model_->lastBadIteration() + 200) { // we can't really trust infeasibilities if there is dual error if (model_->largestDualError() > model_->largestPrimalError()) { tolerance *= CoinMin(model_->largestDualError() / model_->largestPrimalError(), 1000.0); toleranceChanged = true; } } int numberWanted; if (mode_ < 2) { numberWanted = number + 1; } else if (mode_ == 2) { numberWanted = CoinMax(2000, number / 8); } else { int numberElements = model_->factorization()->numberElements(); double ratio = static_cast< double >(numberElements) / static_cast< double >(model_->numberRows()); numberWanted = CoinMax(2000, number / 8); if (ratio < 1.0) { numberWanted = CoinMax(2000, number / 20); } else if (ratio > 10.0) { ratio = number * (ratio / 80.0); if (ratio > number) numberWanted = number + 1; else numberWanted = CoinMax(2000, static_cast< int >(ratio)); } } if (model_->largestPrimalError() > 1.0e-3) numberWanted = number + 1; // be safe int iPass; // Setup two passes int start[4]; start[1] = number; start[2] = 0; double dstart = static_cast< double >(number) * model_->randomNumberGenerator()->randomDouble(); start[0] = static_cast< int >(dstart); start[3] = start[0]; //double largestWeight=0.0; //double smallestWeight=1.0e100; for (iPass = 0; iPass < 2; iPass++) { int end = start[2 * iPass + 1]; for (i = start[2 * iPass]; i < end; i++) { iRow = index[i]; double value = infeas[iRow]; if (value > tolerance) { //#define OUT_EQ #ifdef OUT_EQ { int iSequence = pivotVariable[iRow]; if (upper[iSequence] == lower[iSequence]) value *= 2.0; } #endif double weight = CoinMin(weights_[iRow], 1.0e50); //largestWeight = CoinMax(largestWeight,weight); //smallestWeight = CoinMin(smallestWeight,weight); //double dubious = dubiousWeights_[iRow]; //weight *= dubious; //if (value>2.0*largest*weight||(value>0.5*largest*weight&&value*largestWeight>dubious*largest*weight)) { if (value > largest * weight) { // make last pivot row last resort choice if (iRow == lastPivotRow) { if (value * 1.0e-10 < largest * weight) continue; else value *= 1.0e-10; } int iSequence = pivotVariable[iRow]; if (!model_->flagged(iSequence)) { //#define CLP_DEBUG 3 #ifdef CLP_DEBUG double value2 = 0.0; if (solution[iSequence] > upper[iSequence] + tolerance) value2 = solution[iSequence] - upper[iSequence]; else if (solution[iSequence] < lower[iSequence] - tolerance) value2 = solution[iSequence] - lower[iSequence]; assert(fabs(value2 * value2 - infeas[iRow]) < 1.0e-8 * CoinMin(value2 * value2, infeas[iRow])); #endif if (solution[iSequence] > upper[iSequence] + tolerance || solution[iSequence] < lower[iSequence] - tolerance) { chosenRow = iRow; largest = value / weight; //largestWeight = dubious; } } else { // just to make sure we don't exit before got something numberWanted++; } } numberWanted--; if (!numberWanted) break; } } if (!numberWanted) break; } //printf("smallest %g largest %g\n",smallestWeight,largestWeight); if (chosenRow < 0 && toleranceChanged) { // won't line up with checkPrimalSolution - do again double saveError = model_->largestDualError(); model_->setLargestDualError(0.0); // can't loop chosenRow = pivotRow(); number = infeasible_->getNumElements(); model_->setLargestDualError(saveError); } if (chosenRow < 0 && lastPivotRow < 0) { int nLeft = 0; for (int i = 0; i < number; i++) { int iRow = index[i]; if (fabs(infeas[iRow]) > 1.0e-50) { index[nLeft++] = iRow; } else { infeas[iRow] = 0.0; } } infeasible_->setNumElements(nLeft); model_->setNumberPrimalInfeasibilities(nLeft); } #ifndef NDEBUG //infeasible_->checkClean(); #endif return chosenRow; } #if 0 static double ft_count = 0.0; static double up_count = 0.0; static double ft_count_in = 0.0; static double up_count_in = 0.0; static int xx_count = 0; #endif /* 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; } /* Updates primal solution (and maybe list of candidates) Uses input vector which it deletes Computes change in objective function */ void ClpDualRowSteepest::updatePrimalSolution( CoinIndexedVector *primalUpdate, double primalRatio, double &objectiveChange) { double *COIN_RESTRICT work = primalUpdate->denseVector(); int number = primalUpdate->getNumElements(); int *COIN_RESTRICT which = primalUpdate->getIndices(); int i; double changeObj = 0.0; double tolerance = model_->currentPrimalTolerance(); const int *COIN_RESTRICT pivotVariable = model_->pivotVariable(); double *COIN_RESTRICT infeas = infeasible_->denseVector(); double *COIN_RESTRICT solution = model_->solutionRegion(); const double *COIN_RESTRICT costModel = model_->costRegion(); const double *COIN_RESTRICT lowerModel = model_->lowerRegion(); const double *COIN_RESTRICT upperModel = model_->upperRegion(); #ifdef CLP_DUAL_COLUMN_MULTIPLIER int numberColumns = model_->numberColumns(); #endif if (primalUpdate->packedMode()) { for (i = 0; i < number; i++) { int iRow = which[i]; int iPivot = pivotVariable[iRow]; double value = solution[iPivot]; double cost = costModel[iPivot]; double change = primalRatio * work[i]; work[i] = 0.0; value -= change; changeObj -= change * cost; double lower = lowerModel[iPivot]; double upper = upperModel[iPivot]; solution[iPivot] = value; 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 if (infeas[iRow]) infeas[iRow] = value; // already there else 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 if (infeas[iRow]) infeas[iRow] = value; // already there else infeasible_->quickAdd(iRow, value); } else { // feasible - was it infeasible - if so set tiny if (infeas[iRow]) infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT; } } } else { for (i = 0; i < number; i++) { int iRow = which[i]; int iPivot = pivotVariable[iRow]; double value = solution[iPivot]; double cost = costModel[iPivot]; double change = primalRatio * work[iRow]; value -= change; changeObj -= change * cost; double lower = lowerModel[iPivot]; double upper = upperModel[iPivot]; solution[iPivot] = value; 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 if (infeas[iRow]) infeas[iRow] = value; // already there else 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 if (infeas[iRow]) infeas[iRow] = value; // already there else infeasible_->quickAdd(iRow, value); } else { // feasible - was it infeasible - if so set tiny if (infeas[iRow]) infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT; } work[iRow] = 0.0; } } // Do pivot row { int iRow = model_->pivotRow(); // feasible - was it infeasible - if so set tiny //assert (infeas[iRow]); if (infeas[iRow]) infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT; } primalUpdate->setNumElements(0); objectiveChange += changeObj; } /* Saves any weights round factorization as pivot rows may change 1) before factorization 2) after factorization 3) just redo infeasibilities 4) as 2 but restore weights from previous snapshot 5) for strong branching - initialize to 1 , infeasibilities 6) scale back 7) for strong branching - initialize full weights , infeasibilities */ 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; // clear marker on savedWeights_ assert(savedWeights_); if (savedWeights_->packedMode()) { savedWeights_->setPackedMode(false); savedWeights_->setNumElements(0); } } 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 || mode == 7) { // initialize weights delete[] weights_; delete alternateWeights_; weights_ = new double[numberRows]; // initialize to 1.0 (can we do better?) for (i = 0; i < numberRows; i++) { weights_[i] = 1.0; } alternateWeights_ = new CoinIndexedVector(); // enough space so can use it for factorization alternateWeights_->reserve(numberRows + model_->factorization()->maximumPivots()); if (mode_ != 1 || mode == 5) { } else { CoinIndexedVector *temp = new CoinIndexedVector(); temp->reserve(numberRows + model_->factorization()->maximumPivots()); double *array = alternateWeights_->denseVector(); int *which = alternateWeights_->getIndices(); int firstRow = 0; int lastRow = numberRows; if (mode == 7) { // use info passed in firstRow = model->spareIntArray_[0]; lastRow = model->spareIntArray_[1]; } for (i = firstRow; i < lastRow; 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); for (int i = 0; i < model_->numberRows(); i++) savedWeights_->denseVector()[i] = 1.0; double *array = savedWeights_->denseVector(); int *which = savedWeights_->getIndices(); for (int i = 0; i < numberRows; i++) { array[i] = weights_[i]; which[i] = pivotVariable[i]; } if (mode == 7) { savedWeights_->setNumElements(numberRows); //flag as special savedWeights_->setPackedMode(true); } } 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; } int firstRow = 0; int lastRow = numberRows; if (mode == 7) { // use info passed in firstRow = model->spareIntArray_[0]; lastRow = model->spareIntArray_[1]; } for (i = firstRow; i < lastRow; 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; //printf("bad pivot row %d (%d->%d) iPivot %d\n",i,firstRow,lastRow,iPivot); } } #if 0 printf("mode %d mode_ %d state_ %d\n",mode,mode_,state_); if (!model_->numberIterations()) { for (int k=0;klargestPrimalError(); 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); } } } // see where coming from if (mode == 2 && !model->numberIterations()) { int options = model->specialOptions(); if ((options & 16384) != 0 && true) { // fast of some sort - could be clever??? // for now initialize if ((options & 524288) != 0 && false) { // fathom for (int i = 0; i < numberRows; i++) weights_[i] = 1.0; } else if (true) { // strong for (int i = 0; i < numberRows; i++) weights_[i] = 1.0; } } } } // Pass in saved weights void ClpDualRowSteepest::passInSavedWeights(const CoinIndexedVector *saved) { delete savedWeights_; savedWeights_ = new CoinIndexedVector(*saved); } // Gets rid of last update void ClpDualRowSteepest::unrollWeights() { double *saved = alternateWeights_->denseVector(); int number = alternateWeights_->getNumElements(); int *which = alternateWeights_->getIndices(); int i; if (alternateWeights_->packedMode()) { for (i = 0; i < number; i++) { int iRow = which[i]; weights_[iRow] = saved[i]; saved[i] = 0.0; } } else { for (i = 0; i < number; i++) { int iRow = which[i]; weights_[iRow] = saved[iRow]; saved[iRow] = 0.0; } } alternateWeights_->setNumElements(0); } //------------------------------------------------------------------- // Clone //------------------------------------------------------------------- ClpDualRowPivot *ClpDualRowSteepest::clone(bool CopyData) const { if (CopyData) { return new ClpDualRowSteepest(*this); } else { return new ClpDualRowSteepest(); } } // Gets rid of all arrays void ClpDualRowSteepest::clearArrays() { if (persistence_ == normal) { delete[] weights_; weights_ = NULL; delete[] dubiousWeights_; dubiousWeights_ = NULL; delete infeasible_; infeasible_ = NULL; delete alternateWeights_; alternateWeights_ = NULL; delete savedWeights_; savedWeights_ = NULL; } state_ = -1; } // Returns true if would not find any row bool ClpDualRowSteepest::looksOptimal() const { int iRow; const int *pivotVariable = model_->pivotVariable(); double tolerance = model_->currentPrimalTolerance(); // we can't really trust infeasibilities if there is primal error // this coding has to mimic coding in checkPrimalSolution double error = CoinMin(1.0e-2, model_->largestPrimalError()); // allow tolerance at least slightly bigger than standard tolerance = tolerance + error; // But cap tolerance = CoinMin(1000.0, tolerance); int numberRows = model_->numberRows(); int numberInfeasible = 0; 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) { numberInfeasible++; } else if (value > upper + tolerance) { numberInfeasible++; } } return (numberInfeasible == 0); } // Called when maximum pivots changes void ClpDualRowSteepest::maximumPivotsChanged() { if (alternateWeights_ && alternateWeights_->capacity() != model_->numberRows() + model_->factorization()->maximumPivots()) { delete alternateWeights_; alternateWeights_ = new CoinIndexedVector(); // enough space so can use it for factorization alternateWeights_->reserve(model_->numberRows() + model_->factorization()->maximumPivots()); } } /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2 */