/* $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 #include "CoinPragma.hpp" #include "CoinIndexedVector.hpp" #include "CoinHelperFunctions.hpp" #include "ClpSimplex.hpp" #include "ClpFactorization.hpp" #include "ClpQuadraticObjective.hpp" #include "ClpNonLinearCost.hpp" // at end to get min/max! #include "ClpGubDynamicMatrix.hpp" #include "ClpMessage.hpp" //#define CLP_DEBUG //#define CLP_DEBUG_PRINT //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- ClpGubDynamicMatrix::ClpGubDynamicMatrix() : ClpGubMatrix() , objectiveOffset_(0.0) , startColumn_(NULL) , row_(NULL) , element_(NULL) , cost_(NULL) , fullStart_(NULL) , id_(NULL) , dynamicStatus_(NULL) , lowerColumn_(NULL) , upperColumn_(NULL) , lowerSet_(NULL) , upperSet_(NULL) , numberGubColumns_(0) , firstAvailable_(0) , savedFirstAvailable_(0) , firstDynamic_(0) , lastDynamic_(0) , numberElements_(0) { setType(13); } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- ClpGubDynamicMatrix::ClpGubDynamicMatrix(const ClpGubDynamicMatrix &rhs) : ClpGubMatrix(rhs) { objectiveOffset_ = rhs.objectiveOffset_; numberGubColumns_ = rhs.numberGubColumns_; firstAvailable_ = rhs.firstAvailable_; savedFirstAvailable_ = rhs.savedFirstAvailable_; firstDynamic_ = rhs.firstDynamic_; lastDynamic_ = rhs.lastDynamic_; numberElements_ = rhs.numberElements_; startColumn_ = ClpCopyOfArray(rhs.startColumn_, numberGubColumns_ + 1); CoinBigIndex numberElements = startColumn_[numberGubColumns_]; row_ = ClpCopyOfArray(rhs.row_, numberElements); ; element_ = ClpCopyOfArray(rhs.element_, numberElements); ; cost_ = ClpCopyOfArray(rhs.cost_, numberGubColumns_); fullStart_ = ClpCopyOfArray(rhs.fullStart_, numberSets_ + 1); id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_); lowerColumn_ = ClpCopyOfArray(rhs.lowerColumn_, numberGubColumns_); upperColumn_ = ClpCopyOfArray(rhs.upperColumn_, numberGubColumns_); dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, numberGubColumns_); lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_); upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_); } /* This is the real constructor*/ ClpGubDynamicMatrix::ClpGubDynamicMatrix(ClpSimplex *model, int numberSets, int numberGubColumns, const int *starts, const double *lower, const double *upper, const CoinBigIndex *startColumn, const int *row, const double *element, const double *cost, const double *lowerColumn, const double *upperColumn, const unsigned char *status) : ClpGubMatrix() { objectiveOffset_ = model->objectiveOffset(); model_ = model; numberSets_ = numberSets; numberGubColumns_ = numberGubColumns; fullStart_ = ClpCopyOfArray(starts, numberSets_ + 1); lower_ = ClpCopyOfArray(lower, numberSets_); upper_ = ClpCopyOfArray(upper, numberSets_); int numberColumns = model->numberColumns(); int numberRows = model->numberRows(); // Number of columns needed int numberGubInSmall = numberSets_ + numberRows + 2 * model->factorizationFrequency() + 2; // for small problems this could be too big //numberGubInSmall = CoinMin(numberGubInSmall,numberGubColumns_); int numberNeeded = numberGubInSmall + numberColumns; firstAvailable_ = numberColumns; savedFirstAvailable_ = numberColumns; firstDynamic_ = numberColumns; lastDynamic_ = numberNeeded; startColumn_ = ClpCopyOfArray(startColumn, numberGubColumns_ + 1); CoinBigIndex numberElements = startColumn_[numberGubColumns_]; row_ = ClpCopyOfArray(row, numberElements); element_ = new double[numberElements]; CoinBigIndex i; for (i = 0; i < numberElements; i++) element_[i] = element[i]; cost_ = new double[numberGubColumns_]; for (i = 0; i < numberGubColumns_; i++) { cost_[i] = cost[i]; // need sorted CoinSort_2(row_ + startColumn_[i], row_ + startColumn_[i + 1], element_ + startColumn_[i]); } if (lowerColumn) { lowerColumn_ = new double[numberGubColumns_]; for (i = 0; i < numberGubColumns_; i++) lowerColumn_[i] = lowerColumn[i]; } else { lowerColumn_ = NULL; } if (upperColumn) { upperColumn_ = new double[numberGubColumns_]; for (i = 0; i < numberGubColumns_; i++) upperColumn_[i] = upperColumn[i]; } else { upperColumn_ = NULL; } if (upperColumn || lowerColumn) { lowerSet_ = new double[numberSets_]; for (i = 0; i < numberSets_; i++) { if (lower[i] > -1.0e20) lowerSet_[i] = lower[i]; else lowerSet_[i] = -1.0e30; } upperSet_ = new double[numberSets_]; for (i = 0; i < numberSets_; i++) { if (upper[i] < 1.0e20) upperSet_[i] = upper[i]; else upperSet_[i] = 1.0e30; } } else { lowerSet_ = NULL; upperSet_ = NULL; } start_ = NULL; end_ = NULL; dynamicStatus_ = NULL; id_ = new int[numberGubInSmall]; for (i = 0; i < numberGubInSmall; i++) id_[i] = -1; ClpPackedMatrix *originalMatrixA = dynamic_cast< ClpPackedMatrix * >(model->clpMatrix()); assert(originalMatrixA); CoinPackedMatrix *originalMatrix = originalMatrixA->getPackedMatrix(); originalMatrixA->setMatrixNull(); // so can be deleted safely // guess how much space needed double guess = originalMatrix->getNumElements() + 10; guess /= static_cast< double >(numberColumns); guess *= 2 * numberGubColumns_; numberElements_ = static_cast< int >(CoinMin(guess, 10000000.0)); numberElements_ = CoinMin(numberElements_, numberElements) + originalMatrix->getNumElements(); matrix_ = originalMatrix; flags_ &= ~1; // resize model (matrix stays same) model->resize(numberRows, numberNeeded); if (upperColumn_) { // set all upper bounds so we have enough space double *columnUpper = model->columnUpper(); for (i = firstDynamic_; i < lastDynamic_; i++) columnUpper[i] = 1.0e10; } // resize matrix // extra 1 is so can keep number of elements handy originalMatrix->reserve(numberNeeded, numberElements_, true); originalMatrix->reserve(numberNeeded + 1, numberElements_, false); originalMatrix->getMutableVectorStarts()[numberColumns] = originalMatrix->getNumElements(); // redo number of columns numberColumns = matrix_->getNumCols(); backward_ = new int[numberNeeded]; backToPivotRow_ = new int[numberNeeded]; // We know a bit better delete[] changeCost_; changeCost_ = new double[numberRows + numberSets_]; keyVariable_ = new int[numberSets_]; // signal to need new ordering next_ = NULL; for (int iColumn = 0; iColumn < numberNeeded; iColumn++) backward_[iColumn] = -1; firstGub_ = firstDynamic_; lastGub_ = lastDynamic_; if (!lowerColumn_ && !upperColumn_) gubType_ = 8; if (status) { status_ = ClpCopyOfArray(status, numberSets_); } else { status_ = new unsigned char[numberSets_]; memset(status_, 0, numberSets_); int i; for (i = 0; i < numberSets_; i++) { // make slack key setStatus(i, ClpSimplex::basic); } } saveStatus_ = new unsigned char[numberSets_]; memset(saveStatus_, 0, numberSets_); savedKeyVariable_ = new int[numberSets_]; memset(savedKeyVariable_, 0, numberSets_ * sizeof(int)); } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- ClpGubDynamicMatrix::~ClpGubDynamicMatrix() { delete[] startColumn_; delete[] row_; delete[] element_; delete[] cost_; delete[] fullStart_; delete[] id_; delete[] dynamicStatus_; delete[] lowerColumn_; delete[] upperColumn_; delete[] lowerSet_; delete[] upperSet_; } //---------------------------------------------------------------- // Assignment operator //------------------------------------------------------------------- ClpGubDynamicMatrix & ClpGubDynamicMatrix::operator=(const ClpGubDynamicMatrix &rhs) { if (this != &rhs) { ClpGubMatrix::operator=(rhs); delete[] startColumn_; delete[] row_; delete[] element_; delete[] cost_; delete[] fullStart_; delete[] id_; delete[] dynamicStatus_; delete[] lowerColumn_; delete[] upperColumn_; delete[] lowerSet_; delete[] upperSet_; objectiveOffset_ = rhs.objectiveOffset_; numberGubColumns_ = rhs.numberGubColumns_; firstAvailable_ = rhs.firstAvailable_; savedFirstAvailable_ = rhs.savedFirstAvailable_; firstDynamic_ = rhs.firstDynamic_; lastDynamic_ = rhs.lastDynamic_; numberElements_ = rhs.numberElements_; startColumn_ = ClpCopyOfArray(rhs.startColumn_, numberGubColumns_ + 1); int numberElements = startColumn_[numberGubColumns_]; row_ = ClpCopyOfArray(rhs.row_, numberElements); ; element_ = ClpCopyOfArray(rhs.element_, numberElements); ; cost_ = ClpCopyOfArray(rhs.cost_, numberGubColumns_); fullStart_ = ClpCopyOfArray(rhs.fullStart_, numberSets_ + 1); id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_); lowerColumn_ = ClpCopyOfArray(rhs.lowerColumn_, numberGubColumns_); upperColumn_ = ClpCopyOfArray(rhs.upperColumn_, numberGubColumns_); dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, numberGubColumns_); lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_); upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_); } return *this; } //------------------------------------------------------------------- // Clone //------------------------------------------------------------------- ClpMatrixBase *ClpGubDynamicMatrix::clone() const { return new ClpGubDynamicMatrix(*this); } // Partial pricing void ClpGubDynamicMatrix::partialPricing(ClpSimplex *model, double startFraction, double endFraction, int &bestSequence, int &numberWanted) { assert(!model->rowScale()); numberWanted = currentWanted_; if (!numberSets_) { // no gub ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted); return; } else { // and do some proportion of full set int startG2 = static_cast< int >(startFraction * numberSets_); int endG2 = static_cast< int >(endFraction * numberSets_ + 0.1); endG2 = CoinMin(endG2, numberSets_); //printf("gub price - set start %d end %d\n", // startG2,endG2); double tolerance = model->currentDualTolerance(); double *reducedCost = model->djRegion(); const double *duals = model->dualRowSolution(); double *cost = model->costRegion(); double bestDj; int numberRows = model->numberRows(); int numberColumns = lastDynamic_; // If nothing found yet can go all the way to end int endAll = endG2; if (bestSequence < 0 && !startG2) endAll = numberSets_; if (bestSequence >= 0) bestDj = fabs(reducedCost[bestSequence]); else bestDj = tolerance; int saveSequence = bestSequence; double djMod = 0.0; double infeasibilityCost = model->infeasibilityCost(); double bestDjMod = 0.0; //printf("iteration %d start %d end %d - wanted %d\n",model->numberIterations(), // startG2,endG2,numberWanted); int bestType = -1; int bestSet = -1; const double *element = matrix_->getElements(); const int *row = matrix_->getIndices(); const CoinBigIndex *startColumn = matrix_->getVectorStarts(); int *length = matrix_->getMutableVectorLengths(); #if 0 // make sure first available is clean (in case last iteration rejected) cost[firstAvailable_] = 0.0; length[firstAvailable_] = 0; model->nonLinearCost()->setOne(firstAvailable_, 0.0, 0.0, COIN_DBL_MAX, 0.0); model->setStatus(firstAvailable_, ClpSimplex::atLowerBound); { for (int i = firstAvailable_; i < lastDynamic_; i++) assert(!cost[i]); } #endif #ifdef CLP_DEBUG { for (int i = firstDynamic_; i < firstAvailable_; i++) { assert(getDynamicStatus(id_[i - firstDynamic_]) == inSmall); } } #endif int minSet = minimumObjectsScan_ < 0 ? 5 : minimumObjectsScan_; int minNeg = minimumGoodReducedCosts_ < 0 ? 5 : minimumGoodReducedCosts_; for (int iSet = startG2; iSet < endAll; iSet++) { if (numberWanted + minNeg < originalWanted_ && iSet > startG2 + minSet) { // give up numberWanted = 0; break; } else if (iSet == endG2 && bestSequence >= 0) { break; } CoinBigIndex j; int iBasic = keyVariable_[iSet]; if (iBasic >= numberColumns) { djMod = -weight(iSet) * infeasibilityCost; } else { // get dj without assert(model->getStatus(iBasic) == ClpSimplex::basic); djMod = 0.0; for (j = startColumn[iBasic]; j < startColumn[iBasic] + length[iBasic]; j++) { int jRow = row[j]; djMod -= duals[jRow] * element[j]; } djMod += cost[iBasic]; // See if gub slack possible - dj is djMod if (getStatus(iSet) == ClpSimplex::atLowerBound) { double value = -djMod; if (value > tolerance) { numberWanted--; if (value > bestDj) { // check flagged variable and correct dj if (!flagged(iSet)) { bestDj = value; bestSequence = numberRows + numberColumns + iSet; bestDjMod = djMod; bestType = 0; bestSet = iSet; } else { // just to make sure we don't exit before got something numberWanted++; abort(); } } } } else if (getStatus(iSet) == ClpSimplex::atUpperBound) { double value = djMod; if (value > tolerance) { numberWanted--; if (value > bestDj) { // check flagged variable and correct dj if (!flagged(iSet)) { bestDj = value; bestSequence = numberRows + numberColumns + iSet; bestDjMod = djMod; bestType = 0; bestSet = iSet; } else { // just to make sure we don't exit before got something numberWanted++; abort(); } } } } } for (int iSequence = fullStart_[iSet]; iSequence < fullStart_[iSet + 1]; iSequence++) { DynamicStatus status = getDynamicStatus(iSequence); if (status != inSmall) { double value = cost_[iSequence] - djMod; for (j = startColumn_[iSequence]; j < startColumn_[iSequence + 1]; j++) { int jRow = row_[j]; value -= duals[jRow] * element_[j]; } // change sign if at lower bound if (status == atLowerBound) value = -value; if (value > tolerance) { numberWanted--; if (value > bestDj) { // check flagged variable and correct dj if (!flagged(iSequence)) { bestDj = value; bestSequence = iSequence; bestDjMod = djMod; bestType = 1; bestSet = iSet; } else { // just to make sure we don't exit before got something numberWanted++; } } } } } if (numberWanted <= 0) { numberWanted = 0; break; } } // Do packed part before gub and small gub - but lightly int saveMinNeg = minimumGoodReducedCosts_; int saveSequence2 = bestSequence; if (bestSequence >= 0) minimumGoodReducedCosts_ = -2; int saveLast = lastGub_; lastGub_ = firstAvailable_; currentWanted_ = numberWanted; ClpGubMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted); minimumGoodReducedCosts_ = saveMinNeg; lastGub_ = saveLast; if (bestSequence != saveSequence2) { bestType = -1; // in normal or small gub part saveSequence = bestSequence; } if (bestSequence != saveSequence || bestType >= 0) { double *lowerColumn = model->lowerRegion(); double *upperColumn = model->upperRegion(); double *solution = model->solutionRegion(); if (bestType > 0) { // recompute dj and create double value = cost_[bestSequence] - bestDjMod; for (CoinBigIndex jBigIndex = startColumn_[bestSequence]; jBigIndex < startColumn_[bestSequence + 1]; jBigIndex++) { int jRow = row_[jBigIndex]; value -= duals[jRow] * element_[jBigIndex]; } double *element = matrix_->getMutableElements(); int *row = matrix_->getMutableIndices(); CoinBigIndex *startColumn = matrix_->getMutableVectorStarts(); int *length = matrix_->getMutableVectorLengths(); CoinBigIndex numberElements = startColumn[firstAvailable_]; int numberThis = startColumn_[bestSequence + 1] - startColumn_[bestSequence]; if (numberElements + numberThis > numberElements_) { // need to redo numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis); matrix_->reserve(numberColumns, numberElements_); element = matrix_->getMutableElements(); row = matrix_->getMutableIndices(); // these probably okay but be safe startColumn = matrix_->getMutableVectorStarts(); length = matrix_->getMutableVectorLengths(); } // already set startColumn[firstAvailable_]=numberElements; length[firstAvailable_] = numberThis; model->costRegion()[firstAvailable_] = cost_[bestSequence]; CoinBigIndex base = startColumn_[bestSequence]; for (int j = 0; j < numberThis; j++) { row[numberElements] = row_[base + j]; element[numberElements++] = element_[base + j]; } id_[firstAvailable_ - firstDynamic_] = bestSequence; //printf("best %d\n",bestSequence); backward_[firstAvailable_] = bestSet; model->solutionRegion()[firstAvailable_] = 0.0; if (!lowerColumn_ && !upperColumn_) { model->setStatus(firstAvailable_, ClpSimplex::atLowerBound); lowerColumn[firstAvailable_] = 0.0; upperColumn[firstAvailable_] = COIN_DBL_MAX; } else { DynamicStatus status = getDynamicStatus(bestSequence); if (lowerColumn_) lowerColumn[firstAvailable_] = lowerColumn_[bestSequence]; else lowerColumn[firstAvailable_] = 0.0; if (upperColumn_) upperColumn[firstAvailable_] = upperColumn_[bestSequence]; else upperColumn[firstAvailable_] = COIN_DBL_MAX; if (status == atLowerBound) { solution[firstAvailable_] = lowerColumn[firstAvailable_]; model->setStatus(firstAvailable_, ClpSimplex::atLowerBound); } else { solution[firstAvailable_] = upperColumn[firstAvailable_]; model->setStatus(firstAvailable_, ClpSimplex::atUpperBound); } } model->nonLinearCost()->setOne(firstAvailable_, solution[firstAvailable_], lowerColumn[firstAvailable_], upperColumn[firstAvailable_], cost_[bestSequence]); bestSequence = firstAvailable_; // firstAvailable_ only updated if good pivot (in updatePivot) startColumn[firstAvailable_ + 1] = numberElements; //printf("price struct %d - dj %g gubpi %g\n",bestSequence,value,bestDjMod); reducedCost[bestSequence] = value; gubSlackIn_ = -1; } else { // slack - make last column gubSlackIn_ = bestSequence - numberRows - numberColumns; bestSequence = numberColumns + 2 * numberRows; reducedCost[bestSequence] = bestDjMod; //printf("price slack %d - gubpi %g\n",gubSlackIn_,bestDjMod); model->setStatus(bestSequence, getStatus(gubSlackIn_)); if (getStatus(gubSlackIn_) == ClpSimplex::atUpperBound) solution[bestSequence] = upper_[gubSlackIn_]; else solution[bestSequence] = lower_[gubSlackIn_]; lowerColumn[bestSequence] = lower_[gubSlackIn_]; upperColumn[bestSequence] = upper_[gubSlackIn_]; model->costRegion()[bestSequence] = 0.0; model->nonLinearCost()->setOne(bestSequence, solution[bestSequence], lowerColumn[bestSequence], upperColumn[bestSequence], 0.0); } savedBestSequence_ = bestSequence; savedBestDj_ = reducedCost[savedBestSequence_]; } // See if may be finished if (!startG2 && bestSequence < 0) infeasibilityWeight_ = model_->infeasibilityCost(); else if (bestSequence >= 0) infeasibilityWeight_ = -1.0; } currentWanted_ = numberWanted; } // This is local to Gub to allow synchronization when status is good int ClpGubDynamicMatrix::synchronize(ClpSimplex *model, int mode) { int returnNumber = 0; switch (mode) { case 0: { #ifdef CLP_DEBUG { for (int i = 0; i < numberSets_; i++) assert(toIndex_[i] == -1); } #endif // lookup array int *lookup = new int[lastDynamic_]; int iColumn; int numberColumns = model->numberColumns(); double *element = matrix_->getMutableElements(); int *row = matrix_->getMutableIndices(); CoinBigIndex *startColumn = matrix_->getMutableVectorStarts(); int *length = matrix_->getMutableVectorLengths(); double *cost = model->costRegion(); double *lowerColumn = model->lowerRegion(); double *upperColumn = model->upperRegion(); int *pivotVariable = model->pivotVariable(); CoinBigIndex numberElements = startColumn[firstDynamic_]; // first just do lookup and basic stuff int currentNumber = firstAvailable_; firstAvailable_ = firstDynamic_; int numberToDo = 0; double objectiveChange = 0.0; double *solution = model->solutionRegion(); for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) { int iSet = backward_[iColumn]; if (toIndex_[iSet] < 0) { toIndex_[iSet] = 0; fromIndex_[numberToDo++] = iSet; } if (model->getStatus(iColumn) == ClpSimplex::basic || iColumn == keyVariable_[iSet]) { lookup[iColumn] = firstAvailable_; if (iColumn != keyVariable_[iSet]) { int iPivot = backToPivotRow_[iColumn]; backToPivotRow_[firstAvailable_] = iPivot; pivotVariable[iPivot] = firstAvailable_; } firstAvailable_++; } else { int jColumn = id_[iColumn - firstDynamic_]; setDynamicStatus(jColumn, atLowerBound); if (lowerColumn_ || upperColumn_) { if (model->getStatus(iColumn) == ClpSimplex::atUpperBound) setDynamicStatus(jColumn, atUpperBound); // treat solution as if exactly at a bound double value = solution[iColumn]; if (fabs(value - lowerColumn[iColumn]) < fabs(value - upperColumn[iColumn])) value = lowerColumn[iColumn]; else value = upperColumn[iColumn]; objectiveChange += cost[iColumn] * value; // redo lower and upper on sets double shift = value; if (lowerSet_[iSet] > -1.0e20) lower_[iSet] = lowerSet_[iSet] - shift; if (upperSet_[iSet] < 1.0e20) upper_[iSet] = upperSet_[iSet] - shift; } lookup[iColumn] = -1; } } model->setObjectiveOffset(model->objectiveOffset() + objectiveChange); firstAvailable_ = firstDynamic_; for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) { if (lookup[iColumn] >= 0) { // move int jColumn = id_[iColumn - firstDynamic_]; id_[firstAvailable_ - firstDynamic_] = jColumn; int numberThis = startColumn_[jColumn + 1] - startColumn_[jColumn]; length[firstAvailable_] = numberThis; cost[firstAvailable_] = cost[iColumn]; lowerColumn[firstAvailable_] = lowerColumn[iColumn]; upperColumn[firstAvailable_] = upperColumn[iColumn]; double originalLower = lowerColumn_ ? lowerColumn_[jColumn] : 0.0; double originalUpper = upperColumn_ ? upperColumn_[jColumn] : COIN_DBL_MAX; if (originalUpper > 1.0e30) originalUpper = COIN_DBL_MAX; model->nonLinearCost()->setOne(firstAvailable_, solution[iColumn], originalLower, originalUpper, cost_[jColumn]); CoinBigIndex base = startColumn_[jColumn]; for (int j = 0; j < numberThis; j++) { row[numberElements] = row_[base + j]; element[numberElements++] = element_[base + j]; } model->setStatus(firstAvailable_, model->getStatus(iColumn)); backward_[firstAvailable_] = backward_[iColumn]; solution[firstAvailable_] = solution[iColumn]; firstAvailable_++; startColumn[firstAvailable_] = numberElements; } } // clean up next_ int *temp = new int[firstAvailable_]; for (int jSet = 0; jSet < numberToDo; jSet++) { int iSet = fromIndex_[jSet]; toIndex_[iSet] = -1; int last = keyVariable_[iSet]; int j = next_[last]; bool setTemp = true; if (last < lastDynamic_) { last = lookup[last]; assert(last >= 0); keyVariable_[iSet] = last; } else if (j >= 0) { int newJ = lookup[j]; assert(newJ >= 0); j = next_[j]; next_[last] = newJ; last = newJ; } else { next_[last] = -(iSet + numberColumns + 1); setTemp = false; } while (j >= 0) { int newJ = lookup[j]; assert(newJ >= 0); temp[last] = newJ; last = newJ; j = next_[j]; } if (setTemp) temp[last] = -(keyVariable_[iSet] + 1); if (lowerSet_) { // we only need to get lower_ and upper_ correct double shift = 0.0; for (int j = fullStart_[iSet]; j < fullStart_[iSet + 1]; j++) if (getDynamicStatus(j) == atUpperBound) shift += upperColumn_[j]; else if (getDynamicStatus(j) == atLowerBound && lowerColumn_) shift += lowerColumn_[j]; if (lowerSet_[iSet] > -1.0e20) lower_[iSet] = lowerSet_[iSet] - shift; if (upperSet_[iSet] < 1.0e20) upper_[iSet] = upperSet_[iSet] - shift; } } // move to next_ CoinMemcpyN(temp + firstDynamic_, (firstAvailable_ - firstDynamic_), next_ + firstDynamic_); // if odd iterations may be one out so adjust currentNumber currentNumber = CoinMin(currentNumber + 1, lastDynamic_); // zero solution CoinZeroN(solution + firstAvailable_, currentNumber - firstAvailable_); // zero cost CoinZeroN(cost + firstAvailable_, currentNumber - firstAvailable_); // zero lengths CoinZeroN(length + firstAvailable_, currentNumber - firstAvailable_); for (iColumn = firstAvailable_; iColumn < currentNumber; iColumn++) { model->nonLinearCost()->setOne(iColumn, 0.0, 0.0, COIN_DBL_MAX, 0.0); model->setStatus(iColumn, ClpSimplex::atLowerBound); backward_[iColumn] = -1; } delete[] lookup; delete[] temp; // make sure fromIndex clean fromIndex_[0] = -1; //#define CLP_DEBUG #ifdef CLP_DEBUG // debug { int i; int numberRows = model->numberRows(); char *xxxx = new char[numberColumns]; memset(xxxx, 0, numberColumns); for (i = 0; i < numberRows; i++) { int iPivot = pivotVariable[i]; assert(model->getStatus(iPivot) == ClpSimplex::basic); if (iPivot < numberColumns && backward_[iPivot] >= 0) xxxx[iPivot] = 1; } for (i = 0; i < numberSets_; i++) { int key = keyVariable_[i]; int iColumn = next_[key]; int k = 0; while (iColumn >= 0) { k++; assert(k < 100); assert(backward_[iColumn] == i); iColumn = next_[iColumn]; } int stop = -(key + 1); while (iColumn != stop) { assert(iColumn < 0); iColumn = -iColumn - 1; k++; assert(k < 100); assert(backward_[iColumn] == i); iColumn = next_[iColumn]; } iColumn = next_[key]; while (iColumn >= 0) { assert(xxxx[iColumn]); xxxx[iColumn] = 0; iColumn = next_[iColumn]; } } for (i = 0; i < numberColumns; i++) { if (i < numberColumns && backward_[i] >= 0) { assert(!xxxx[i] || i == keyVariable_[backward_[i]]); } } delete[] xxxx; } { for (int i = 0; i < numberSets_; i++) assert(toIndex_[i] == -1); } #endif savedFirstAvailable_ = firstAvailable_; } break; // flag a variable case 1: { // id will be sitting at firstAvailable int sequence = id_[firstAvailable_ - firstDynamic_]; assert(!flagged(sequence)); setFlagged(sequence); model->clearFlagged(firstAvailable_); } break; // unflag all variables case 2: { for (int i = 0; i < numberGubColumns_; i++) { if (flagged(i)) { unsetFlagged(i); returnNumber++; } } } break; // just reset costs and bounds (primal) case 3: { double *cost = model->costRegion(); double *solution = model->solutionRegion(); double *lowerColumn = model->columnLower(); double *upperColumn = model->columnUpper(); for (int i = firstDynamic_; i < firstAvailable_; i++) { int jColumn = id_[i - firstDynamic_]; cost[i] = cost_[jColumn]; if (!lowerColumn_ && !upperColumn_) { lowerColumn[i] = 0.0; upperColumn[i] = COIN_DBL_MAX; } else { if (lowerColumn_) lowerColumn[i] = lowerColumn_[jColumn]; else lowerColumn[i] = 0.0; if (upperColumn_) upperColumn[i] = upperColumn_[jColumn]; else upperColumn[i] = COIN_DBL_MAX; } if (model->nonLinearCost()) model->nonLinearCost()->setOne(i, solution[i], lowerColumn[i], upperColumn[i], cost_[jColumn]); } if (!model->numberIterations() && rhsOffset_) { lastRefresh_ = -refreshFrequency_; // force refresh } } break; // and get statistics for column generation case 4: { // In theory we should subtract out ones we have done but .... // If key slack then dual 0.0 // If not then slack could be dual infeasible // dj for key is zero so that defines dual on set int i; int numberColumns = model->numberColumns(); double *dual = model->dualRowSolution(); double infeasibilityCost = model->infeasibilityCost(); double dualTolerance = model->dualTolerance(); double relaxedTolerance = dualTolerance; // we can't really trust infeasibilities if there is dual error double error = CoinMin(1.0e-2, model->largestDualError()); // allow tolerance at least slightly bigger than standard relaxedTolerance = relaxedTolerance + error; // but we will be using difference relaxedTolerance -= dualTolerance; double objectiveOffset = 0.0; for (i = 0; i < numberSets_; i++) { int kColumn = keyVariable_[i]; double value = 0.0; if (kColumn < numberColumns) { kColumn = id_[kColumn - firstDynamic_]; // dj without set value = cost_[kColumn]; for (CoinBigIndex j = startColumn_[kColumn]; j < startColumn_[kColumn + 1]; j++) { int iRow = row_[j]; value -= dual[iRow] * element_[j]; } double infeasibility = 0.0; if (getStatus(i) == ClpSimplex::atLowerBound) { if (-value > dualTolerance) infeasibility = -value - dualTolerance; } else if (getStatus(i) == ClpSimplex::atUpperBound) { if (value > dualTolerance) infeasibility = value - dualTolerance; } if (infeasibility > 0.0) { sumDualInfeasibilities_ += infeasibility; if (infeasibility > relaxedTolerance) sumOfRelaxedDualInfeasibilities_ += infeasibility; numberDualInfeasibilities_++; } } else { // slack key - may not be feasible assert(getStatus(i) == ClpSimplex::basic); // negative as -1.0 for slack value = -weight(i) * infeasibilityCost; } // Now subtract out from all for (CoinBigIndex k = fullStart_[i]; k < fullStart_[i + 1]; k++) { if (getDynamicStatus(k) != inSmall) { double djValue = cost_[k] - value; for (CoinBigIndex j = startColumn_[k]; j < startColumn_[k + 1]; j++) { int iRow = row_[j]; djValue -= dual[iRow] * element_[j]; } double infeasibility = 0.0; double shift = 0.0; if (getDynamicStatus(k) == atLowerBound) { if (lowerColumn_) shift = lowerColumn_[k]; if (djValue < -dualTolerance) infeasibility = -djValue - dualTolerance; } else { // at upper bound shift = upperColumn_[k]; if (djValue > dualTolerance) infeasibility = djValue - dualTolerance; } objectiveOffset += shift * cost_[k]; if (infeasibility > 0.0) { sumDualInfeasibilities_ += infeasibility; if (infeasibility > relaxedTolerance) sumOfRelaxedDualInfeasibilities_ += infeasibility; numberDualInfeasibilities_++; } } } } model->setObjectiveOffset(objectiveOffset_ - objectiveOffset); } break; // see if time to re-factorize case 5: { if (firstAvailable_ > numberSets_ + model->numberRows() + model->factorizationFrequency()) returnNumber = 4; } break; // return 1 if there may be changing bounds on variable (column generation) case 6: { returnNumber = (lowerColumn_ != NULL || upperColumn_ != NULL) ? 1 : 0; #if 0 if (!returnNumber) { // may be gub slacks for (int i = 0; i < numberSets_; i++) { if (upper_[i] > lower_[i]) { returnNumber = 1; break; } } } #endif } break; // restore firstAvailable_ case 7: { int iColumn; int *length = matrix_->getMutableVectorLengths(); double *cost = model->costRegion(); double *solution = model->solutionRegion(); int currentNumber = firstAvailable_; firstAvailable_ = savedFirstAvailable_; // zero solution CoinZeroN(solution + firstAvailable_, currentNumber - firstAvailable_); // zero cost CoinZeroN(cost + firstAvailable_, currentNumber - firstAvailable_); // zero lengths CoinZeroN(length + firstAvailable_, currentNumber - firstAvailable_); for (iColumn = firstAvailable_; iColumn < currentNumber; iColumn++) { model->nonLinearCost()->setOne(iColumn, 0.0, 0.0, COIN_DBL_MAX, 0.0); model->setStatus(iColumn, ClpSimplex::atLowerBound); backward_[iColumn] = -1; } } break; // make sure set is clean case 8: { int sequenceIn = model->sequenceIn(); if (sequenceIn < model->numberColumns()) { int iSet = backward_[sequenceIn]; if (iSet >= 0 && lowerSet_) { // we only need to get lower_ and upper_ correct double shift = 0.0; for (int j = fullStart_[iSet]; j < fullStart_[iSet + 1]; j++) if (getDynamicStatus(j) == atUpperBound) shift += upperColumn_[j]; else if (getDynamicStatus(j) == atLowerBound && lowerColumn_) shift += lowerColumn_[j]; if (lowerSet_[iSet] > -1.0e20) lower_[iSet] = lowerSet_[iSet] - shift; if (upperSet_[iSet] < 1.0e20) upper_[iSet] = upperSet_[iSet] - shift; } if (sequenceIn == firstAvailable_) { // not really in small problem int iBig = id_[sequenceIn - firstDynamic_]; if (model->getStatus(sequenceIn) == ClpSimplex::atLowerBound) setDynamicStatus(iBig, atLowerBound); else setDynamicStatus(iBig, atUpperBound); } } } break; // adjust lower,upper case 9: { int sequenceIn = model->sequenceIn(); if (sequenceIn >= firstDynamic_ && sequenceIn < lastDynamic_ && lowerSet_) { int iSet = backward_[sequenceIn]; assert(iSet >= 0); int inBig = id_[sequenceIn - firstDynamic_]; const double *solution = model->solutionRegion(); setDynamicStatus(inBig, inSmall); if (lowerSet_[iSet] > -1.0e20) lower_[iSet] += solution[sequenceIn]; if (upperSet_[iSet] < 1.0e20) upper_[iSet] += solution[sequenceIn]; model->setObjectiveOffset(model->objectiveOffset() - solution[sequenceIn] * cost_[inBig]); } } } return returnNumber; } // Add a new variable to a set void ClpGubDynamicMatrix::insertNonBasic(int sequence, int iSet) { int last = keyVariable_[iSet]; int j = next_[last]; while (j >= 0) { last = j; j = next_[j]; } next_[last] = -(sequence + 1); next_[sequence] = j; } // Sets up an effective RHS and does gub crash if needed void ClpGubDynamicMatrix::useEffectiveRhs(ClpSimplex *model, bool cheapest) { // Do basis - cheapest or slack if feasible (unless cheapest set) int longestSet = 0; int iSet; for (iSet = 0; iSet < numberSets_; iSet++) longestSet = CoinMax(longestSet, fullStart_[iSet + 1] - fullStart_[iSet]); double *upper = new double[longestSet + 1]; double *cost = new double[longestSet + 1]; double *lower = new double[longestSet + 1]; double *solution = new double[longestSet + 1]; assert(!next_); delete[] next_; int numberColumns = model->numberColumns(); next_ = new int[numberColumns + numberSets_ + CoinMax(2 * longestSet, lastDynamic_ - firstDynamic_)]; char *mark = new char[numberColumns]; memset(mark, 0, numberColumns); for (int iColumn = 0; iColumn < numberColumns; iColumn++) next_[iColumn] = COIN_INT_MAX; int i; int *keys = new int[numberSets_]; int *back = new int[numberGubColumns_]; CoinFillN(back, numberGubColumns_, -1); for (i = 0; i < numberSets_; i++) keys[i] = COIN_INT_MAX; delete[] dynamicStatus_; dynamicStatus_ = new unsigned char[numberGubColumns_]; memset(dynamicStatus_, 0, numberGubColumns_); // for clarity for (i = 0; i < numberGubColumns_; i++) setDynamicStatus(i, atLowerBound); // set up chains for (i = firstDynamic_; i < lastDynamic_; i++) { if (id_[i - firstDynamic_] >= 0) { if (model->getStatus(i) == ClpSimplex::basic) mark[i] = 1; int iSet = backward_[i]; assert(iSet >= 0); int iNext = keys[iSet]; next_[i] = iNext; keys[iSet] = i; back[id_[i - firstDynamic_]] = i; } else { model->setStatus(i, ClpSimplex::atLowerBound); backward_[i] = -1; } } double *columnSolution = model->solutionRegion(); int numberRows = getNumRows(); toIndex_ = new int[numberSets_]; for (iSet = 0; iSet < numberSets_; iSet++) toIndex_[iSet] = -1; fromIndex_ = new int[numberRows + numberSets_]; double tolerance = model->primalTolerance(); double *element = matrix_->getMutableElements(); int *row = matrix_->getMutableIndices(); CoinBigIndex *startColumn = matrix_->getMutableVectorStarts(); int *length = matrix_->getMutableVectorLengths(); double objectiveOffset = 0.0; for (iSet = 0; iSet < numberSets_; iSet++) { int j; int numberBasic = 0; int iBasic = -1; int iStart = fullStart_[iSet]; int iEnd = fullStart_[iSet + 1]; // find one with smallest length int smallest = numberRows + 1; double value = 0.0; j = keys[iSet]; while (j != COIN_INT_MAX) { if (model->getStatus(j) == ClpSimplex::basic) { if (length[j] < smallest) { smallest = length[j]; iBasic = j; } numberBasic++; } value += columnSolution[j]; j = next_[j]; } bool done = false; if (numberBasic > 1 || (numberBasic == 1 && getStatus(iSet) == ClpSimplex::basic)) { if (getStatus(iSet) == ClpSimplex::basic) iBasic = iSet + numberColumns; // slack key - use done = true; } else if (numberBasic == 1) { // see if can be key double thisSolution = columnSolution[iBasic]; if (thisSolution < 0.0) { value -= thisSolution; thisSolution = 0.0; columnSolution[iBasic] = thisSolution; } // try setting slack to a bound assert(upper_[iSet] < 1.0e20 || lower_[iSet] > -1.0e20); double cost1 = COIN_DBL_MAX; int whichBound = -1; if (upper_[iSet] < 1.0e20) { // try slack at ub double newBasic = thisSolution + upper_[iSet] - value; if (newBasic >= -tolerance) { // can go whichBound = 1; cost1 = newBasic * cost_[iBasic]; // But if exact then may be good solution if (fabs(upper_[iSet] - value) < tolerance) cost1 = -COIN_DBL_MAX; } } if (lower_[iSet] > -1.0e20) { // try slack at lb double newBasic = thisSolution + lower_[iSet] - value; if (newBasic >= -tolerance) { // can go but is it cheaper double cost2 = newBasic * cost_[iBasic]; // But if exact then may be good solution if (fabs(lower_[iSet] - value) < tolerance) cost2 = -COIN_DBL_MAX; if (cost2 < cost1) whichBound = 0; } } if (whichBound != -1) { // key done = true; if (whichBound) { // slack to upper columnSolution[iBasic] = thisSolution + upper_[iSet] - value; setStatus(iSet, ClpSimplex::atUpperBound); } else { // slack to lower columnSolution[iBasic] = thisSolution + lower_[iSet] - value; setStatus(iSet, ClpSimplex::atLowerBound); } } } if (!done) { if (!cheapest) { // see if slack can be key if (value >= lower_[iSet] - tolerance && value <= upper_[iSet] + tolerance) { done = true; setStatus(iSet, ClpSimplex::basic); iBasic = iSet + numberColumns; } } if (!done) { // set non basic if there was one if (iBasic >= 0) model->setStatus(iBasic, ClpSimplex::atLowerBound); // find cheapest int numberInSet = iEnd - iStart; if (!lowerColumn_) { CoinZeroN(lower, numberInSet); } else { for (int j = 0; j < numberInSet; j++) lower[j] = lowerColumn_[j + iStart]; } if (!upperColumn_) { CoinFillN(upper, numberInSet, COIN_DBL_MAX); } else { for (int j = 0; j < numberInSet; j++) upper[j] = upperColumn_[j + iStart]; } CoinFillN(solution, numberInSet, 0.0); // and slack iBasic = numberInSet; solution[iBasic] = -value; lower[iBasic] = -upper_[iSet]; upper[iBasic] = -lower_[iSet]; int kphase; if (value >= lower_[iSet] - tolerance && value <= upper_[iSet] + tolerance) { // feasible kphase = 1; cost[iBasic] = 0.0; for (int j = 0; j < numberInSet; j++) cost[j] = cost_[j + iStart]; } else { // infeasible kphase = 0; // remember bounds are flipped so opposite to natural if (value < lower_[iSet] - tolerance) cost[iBasic] = 1.0; else cost[iBasic] = -1.0; CoinZeroN(cost, numberInSet); } double dualTolerance = model->dualTolerance(); for (int iphase = kphase; iphase < 2; iphase++) { if (iphase) { cost[numberInSet] = 0.0; for (int j = 0; j < numberInSet; j++) cost[j] = cost_[j + iStart]; } // now do one row lp bool improve = true; while (improve) { improve = false; double dual = cost[iBasic]; int chosen = -1; double best = dualTolerance; int way = 0; for (int i = 0; i <= numberInSet; i++) { double dj = cost[i] - dual; double improvement = 0.0; if (iphase || i < numberInSet) assert(solution[i] >= lower[i] && solution[i] <= upper[i]); if (dj > dualTolerance) improvement = dj * (solution[i] - lower[i]); else if (dj < -dualTolerance) improvement = dj * (solution[i] - upper[i]); if (improvement > best) { best = improvement; chosen = i; if (dj < 0.0) { way = 1; } else { way = -1; } } } if (chosen >= 0) { improve = true; // now see how far if (way > 0) { // incoming increasing so basic decreasing // if phase 0 then go to nearest bound double distance = upper[chosen] - solution[chosen]; double basicDistance; if (!iphase) { assert(iBasic == numberInSet); assert(solution[iBasic] > upper[iBasic]); basicDistance = solution[iBasic] - upper[iBasic]; } else { basicDistance = solution[iBasic] - lower[iBasic]; } // need extra coding for unbounded assert(CoinMin(distance, basicDistance) < 1.0e20); if (distance > basicDistance) { // incoming becomes basic solution[chosen] += basicDistance; if (!iphase) solution[iBasic] = upper[iBasic]; else solution[iBasic] = lower[iBasic]; iBasic = chosen; } else { // flip solution[chosen] = upper[chosen]; solution[iBasic] -= distance; } } else { // incoming decreasing so basic increasing // if phase 0 then go to nearest bound double distance = solution[chosen] - lower[chosen]; double basicDistance; if (!iphase) { assert(iBasic == numberInSet); assert(solution[iBasic] < lower[iBasic]); basicDistance = lower[iBasic] - solution[iBasic]; } else { basicDistance = upper[iBasic] - solution[iBasic]; } // need extra coding for unbounded - for now just exit if (CoinMin(distance, basicDistance) > 1.0e20) { printf("unbounded on set %d\n", iSet); iphase = 1; iBasic = numberInSet; break; } if (distance > basicDistance) { // incoming becomes basic solution[chosen] -= basicDistance; if (!iphase) solution[iBasic] = lower[iBasic]; else solution[iBasic] = upper[iBasic]; iBasic = chosen; } else { // flip solution[chosen] = lower[chosen]; solution[iBasic] += distance; } } if (!iphase) { if (iBasic < numberInSet) break; // feasible else if (solution[iBasic] >= lower[iBasic] && solution[iBasic] <= upper[iBasic]) break; // feasible (on flip) } } } } // do solution i.e. bounds if (lowerColumn_ || upperColumn_) { for (int j = 0; j < numberInSet; j++) { if (j != iBasic) { objectiveOffset += solution[j] * cost[j]; if (lowerColumn_ && upperColumn_) { if (fabs(solution[j] - lowerColumn_[j + iStart]) > fabs(solution[j] - upperColumn_[j + iStart])) setDynamicStatus(j + iStart, atUpperBound); } else if (upperColumn_ && solution[j] > 0.0) { setDynamicStatus(j + iStart, atUpperBound); } else { setDynamicStatus(j + iStart, atLowerBound); } } } } // convert iBasic back and do bounds if (iBasic == numberInSet) { // slack basic setStatus(iSet, ClpSimplex::basic); iBasic = iSet + numberColumns; } else { iBasic += fullStart_[iSet]; if (back[iBasic] >= 0) { // exists iBasic = back[iBasic]; } else { // create CoinBigIndex numberElements = startColumn[firstAvailable_]; int numberThis = startColumn_[iBasic + 1] - startColumn_[iBasic]; if (numberElements + numberThis > numberElements_) { // need to redo numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis); matrix_->reserve(numberColumns, numberElements_); element = matrix_->getMutableElements(); row = matrix_->getMutableIndices(); // these probably okay but be safe startColumn = matrix_->getMutableVectorStarts(); length = matrix_->getMutableVectorLengths(); } length[firstAvailable_] = numberThis; model->costRegion()[firstAvailable_] = cost_[iBasic]; if (lowerColumn_) model->lowerRegion()[firstAvailable_] = lowerColumn_[iBasic]; else model->lowerRegion()[firstAvailable_] = 0.0; if (upperColumn_) model->upperRegion()[firstAvailable_] = upperColumn_[iBasic]; else model->upperRegion()[firstAvailable_] = COIN_DBL_MAX; columnSolution[firstAvailable_] = solution[iBasic - fullStart_[iSet]]; CoinBigIndex base = startColumn_[iBasic]; for (int j = 0; j < numberThis; j++) { row[numberElements] = row_[base + j]; element[numberElements++] = element_[base + j]; } // already set startColumn[firstAvailable_]=numberElements; id_[firstAvailable_ - firstDynamic_] = iBasic; setDynamicStatus(iBasic, inSmall); backward_[firstAvailable_] = iSet; iBasic = firstAvailable_; firstAvailable_++; startColumn[firstAvailable_] = numberElements; } model->setStatus(iBasic, ClpSimplex::basic); // remember bounds flipped if (upper[numberInSet] == lower[numberInSet]) setStatus(iSet, ClpSimplex::isFixed); else if (solution[numberInSet] == upper[numberInSet]) setStatus(iSet, ClpSimplex::atLowerBound); else if (solution[numberInSet] == lower[numberInSet]) setStatus(iSet, ClpSimplex::atUpperBound); else abort(); } for (j = iStart; j < iEnd; j++) { int iBack = back[j]; if (iBack >= 0) { if (model->getStatus(iBack) != ClpSimplex::basic) { int inSet = j - iStart; columnSolution[iBack] = solution[inSet]; if (upper[inSet] == lower[inSet]) model->setStatus(iBack, ClpSimplex::isFixed); else if (solution[inSet] == upper[inSet]) model->setStatus(iBack, ClpSimplex::atUpperBound); else if (solution[inSet] == lower[inSet]) model->setStatus(iBack, ClpSimplex::atLowerBound); } } } } } keyVariable_[iSet] = iBasic; } model->setObjectiveOffset(objectiveOffset_ - objectiveOffset); delete[] lower; delete[] solution; delete[] upper; delete[] cost; // make sure matrix is in good shape matrix_->orderMatrix(); // create effective rhs delete[] rhsOffset_; rhsOffset_ = new double[numberRows]; // and redo chains memset(mark, 0, numberColumns); for (int iColumnX = 0; iColumnX < firstAvailable_; iColumnX++) next_[iColumnX] = COIN_INT_MAX; for (i = 0; i < numberSets_; i++) { keys[i] = COIN_INT_MAX; int iKey = keyVariable_[i]; if (iKey < numberColumns) model->setStatus(iKey, ClpSimplex::basic); } // set up chains for (i = 0; i < firstAvailable_; i++) { if (model->getStatus(i) == ClpSimplex::basic) mark[i] = 1; int iSet = backward_[i]; if (iSet >= 0) { int iNext = keys[iSet]; next_[i] = iNext; keys[iSet] = i; } } for (i = 0; i < numberSets_; i++) { if (keys[i] != COIN_INT_MAX) { // something in set int j; if (getStatus(i) != ClpSimplex::basic) { // make sure fixed if it is if (upper_[i] == lower_[i]) setStatus(i, ClpSimplex::isFixed); // slack not key - choose one with smallest length int smallest = numberRows + 1; int key = -1; j = keys[i]; while (1) { if (mark[j] && length[j] < smallest) { key = j; smallest = length[j]; } if (next_[j] != COIN_INT_MAX) { j = next_[j]; } else { // correct end next_[j] = -(keys[i] + 1); break; } } if (key >= 0) { keyVariable_[i] = key; } else { // nothing basic - make slack key //((ClpGubMatrix *)this)->setStatus(i,ClpSimplex::basic); // fudge to avoid const problem status_[i] = 1; } } else { // slack key keyVariable_[i] = numberColumns + i; int j; double sol = 0.0; j = keys[i]; while (1) { sol += columnSolution[j]; if (next_[j] != COIN_INT_MAX) { j = next_[j]; } else { // correct end next_[j] = -(keys[i] + 1); break; } } if (sol > upper_[i] + tolerance) { setAbove(i); } else if (sol < lower_[i] - tolerance) { setBelow(i); } else { setFeasible(i); } } // Create next_ int key = keyVariable_[i]; redoSet(model, key, keys[i], i); } else { // nothing in set! next_[i + numberColumns] = -(i + numberColumns + 1); keyVariable_[i] = numberColumns + i; double sol = 0.0; if (sol > upper_[i] + tolerance) { setAbove(i); } else if (sol < lower_[i] - tolerance) { setBelow(i); } else { setFeasible(i); } } } delete[] keys; delete[] mark; delete[] back; rhsOffset(model, true); } /* Returns effective RHS if it is being used. This is used for long problems or big gub or anywhere where going through full columns is expensive. This may re-compute */ double * ClpGubDynamicMatrix::rhsOffset(ClpSimplex *model, bool forceRefresh, bool #ifdef CLP_DEBUG check #endif ) { //forceRefresh=true; //check=false; #ifdef CLP_DEBUG double *saveE = NULL; if (rhsOffset_ && check) { int numberRows = model->numberRows(); saveE = new double[numberRows]; } #endif if (rhsOffset_) { #ifdef CLP_DEBUG if (check) { // no need - but check anyway int numberRows = model->numberRows(); double *rhs = new double[numberRows]; int numberColumns = model->numberColumns(); int iRow; CoinZeroN(rhs, numberRows); // do ones at bounds before gub const double *smallSolution = model->solutionRegion(); const double *element = matrix_->getElements(); const int *row = matrix_->getIndices(); const CoinBigIndex *startColumn = matrix_->getVectorStarts(); const int *length = matrix_->getVectorLengths(); int iColumn; for (iColumn = 0; iColumn < firstDynamic_; iColumn++) { if (model->getStatus(iColumn) != ClpSimplex::basic) { double value = smallSolution[iColumn]; for (CoinBigIndex j = startColumn[iColumn]; j < startColumn[iColumn] + length[iColumn]; j++) { int jRow = row[j]; rhs[jRow] -= value * element[j]; } } } if (lowerColumn_ || upperColumn_) { double *solution = new double[numberGubColumns_]; for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) { double value = 0.0; if (getDynamicStatus(iColumn) == atUpperBound) value = upperColumn_[iColumn]; else if (lowerColumn_) value = lowerColumn_[iColumn]; solution[iColumn] = value; } // ones at bounds in small and gub for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) { int jFull = id_[iColumn - firstDynamic_]; solution[jFull] = smallSolution[iColumn]; } // zero all basic in small model int *pivotVariable = model->pivotVariable(); for (iRow = 0; iRow < numberRows; iRow++) { int iColumn = pivotVariable[iRow]; if (iColumn >= firstDynamic_ && iColumn < lastDynamic_) { int iSequence = id_[iColumn - firstDynamic_]; solution[iSequence] = 0.0; } } // and now compute value to use for key ClpSimplex::Status iStatus; for (int iSet = 0; iSet < numberSets_; iSet++) { iColumn = keyVariable_[iSet]; if (iColumn < numberColumns) { int iSequence = id_[iColumn - firstDynamic_]; solution[iSequence] = 0.0; double b = 0.0; // key is structural - where is slack iStatus = getStatus(iSet); assert(iStatus != ClpSimplex::basic); if (iStatus == ClpSimplex::atLowerBound) b = lowerSet_[iSet]; else b = upperSet_[iSet]; // subtract out others at bounds for (int j = fullStart_[iSet]; j < fullStart_[iSet + 1]; j++) b -= solution[j]; solution[iSequence] = b; } } for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) { double value = solution[iColumn]; if (value) { for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn + 1]; j++) { int iRow = row_[j]; rhs[iRow] -= element_[j] * value; } } } // now do lower and upper bounds on sets for (int iSet = 0; iSet < numberSets_; iSet++) { iColumn = keyVariable_[iSet]; double shift = 0.0; for (int j = fullStart_[iSet]; j < fullStart_[iSet + 1]; j++) { if (getDynamicStatus(j) != inSmall && j != iColumn) { if (getDynamicStatus(j) == atLowerBound) { if (lowerColumn_) shift += lowerColumn_[j]; } else { shift += upperColumn_[j]; } } } if (lowerSet_[iSet] > -1.0e20) assert(fabs(lower_[iSet] - (lowerSet_[iSet] - shift)) < 1.0e-3); if (upperSet_[iSet] < 1.0e20) assert(fabs(upper_[iSet] - (upperSet_[iSet] - shift)) < 1.0e-3); } delete[] solution; } else { // no bounds ClpSimplex::Status iStatus; for (int iSet = 0; iSet < numberSets_; iSet++) { int iColumn = keyVariable_[iSet]; if (iColumn < numberColumns) { int iSequence = id_[iColumn - firstDynamic_]; double b = 0.0; // key is structural - where is slack iStatus = getStatus(iSet); assert(iStatus != ClpSimplex::basic); if (iStatus == ClpSimplex::atLowerBound) b = lower_[iSet]; else b = upper_[iSet]; if (b) { for (CoinBigIndex j = startColumn_[iSequence]; j < startColumn_[iSequence + 1]; j++) { int iRow = row_[j]; rhs[iRow] -= element_[j] * b; } } } } } for (iRow = 0; iRow < numberRows; iRow++) { if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3) printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]); } CoinMemcpyN(rhs, numberRows, saveE); delete[] rhs; } #endif if (forceRefresh || (refreshFrequency_ && model->numberIterations() >= lastRefresh_ + refreshFrequency_)) { int numberRows = model->numberRows(); int numberColumns = model->numberColumns(); int iRow; CoinZeroN(rhsOffset_, numberRows); // do ones at bounds before gub const double *smallSolution = model->solutionRegion(); const double *element = matrix_->getElements(); const int *row = matrix_->getIndices(); const CoinBigIndex *startColumn = matrix_->getVectorStarts(); const int *length = matrix_->getVectorLengths(); int iColumn; for (iColumn = 0; iColumn < firstDynamic_; iColumn++) { if (model->getStatus(iColumn) != ClpSimplex::basic) { double value = smallSolution[iColumn]; for (CoinBigIndex j = startColumn[iColumn]; j < startColumn[iColumn] + length[iColumn]; j++) { int jRow = row[j]; rhsOffset_[jRow] -= value * element[j]; } } } if (lowerColumn_ || upperColumn_) { double *solution = new double[numberGubColumns_]; for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) { double value = 0.0; if (getDynamicStatus(iColumn) == atUpperBound) value = upperColumn_[iColumn]; else if (lowerColumn_) value = lowerColumn_[iColumn]; solution[iColumn] = value; } // ones in gub and in small problem for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) { int jFull = id_[iColumn - firstDynamic_]; solution[jFull] = smallSolution[iColumn]; } // zero all basic in small model int *pivotVariable = model->pivotVariable(); for (iRow = 0; iRow < numberRows; iRow++) { int iColumn = pivotVariable[iRow]; if (iColumn >= firstDynamic_ && iColumn < lastDynamic_) { int iSequence = id_[iColumn - firstDynamic_]; solution[iSequence] = 0.0; } } // and now compute value to use for key ClpSimplex::Status iStatus; int iSet; for (iSet = 0; iSet < numberSets_; iSet++) { iColumn = keyVariable_[iSet]; if (iColumn < numberColumns) { int iSequence = id_[iColumn - firstDynamic_]; solution[iSequence] = 0.0; double b = 0.0; // key is structural - where is slack iStatus = getStatus(iSet); assert(iStatus != ClpSimplex::basic); if (iStatus == ClpSimplex::atLowerBound) b = lowerSet_[iSet]; else b = upperSet_[iSet]; // subtract out others at bounds for (int j = fullStart_[iSet]; j < fullStart_[iSet + 1]; j++) b -= solution[j]; solution[iSequence] = b; } } for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) { double value = solution[iColumn]; if (value) { for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn + 1]; j++) { int iRow = row_[j]; rhsOffset_[iRow] -= element_[j] * value; } } } // now do lower and upper bounds on sets // and offset double objectiveOffset = 0.0; for (iSet = 0; iSet < numberSets_; iSet++) { iColumn = keyVariable_[iSet]; double shift = 0.0; for (CoinBigIndex j = fullStart_[iSet]; j < fullStart_[iSet + 1]; j++) { if (getDynamicStatus(j) != inSmall) { double value = 0.0; if (getDynamicStatus(j) == atLowerBound) { if (lowerColumn_) value = lowerColumn_[j]; } else { value = upperColumn_[j]; } if (j != iColumn) shift += value; objectiveOffset += value * cost_[j]; } } if (lowerSet_[iSet] > -1.0e20) lower_[iSet] = lowerSet_[iSet] - shift; if (upperSet_[iSet] < 1.0e20) upper_[iSet] = upperSet_[iSet] - shift; } delete[] solution; model->setObjectiveOffset(objectiveOffset_ - objectiveOffset); } else { // no bounds ClpSimplex::Status iStatus; for (int iSet = 0; iSet < numberSets_; iSet++) { int iColumn = keyVariable_[iSet]; if (iColumn < numberColumns) { int iSequence = id_[iColumn - firstDynamic_]; double b = 0.0; // key is structural - where is slack iStatus = getStatus(iSet); assert(iStatus != ClpSimplex::basic); if (iStatus == ClpSimplex::atLowerBound) b = lower_[iSet]; else b = upper_[iSet]; if (b) { for (CoinBigIndex j = startColumn_[iSequence]; j < startColumn_[iSequence + 1]; j++) { int iRow = row_[j]; rhsOffset_[iRow] -= element_[j] * b; } } } } } #ifdef CLP_DEBUG if (saveE) { for (iRow = 0; iRow < numberRows; iRow++) { if (fabs(saveE[iRow] - rhsOffset_[iRow]) > 1.0e-3) printf("** %d - old eff %g new %g\n", iRow, saveE[iRow], rhsOffset_[iRow]); } delete[] saveE; } #endif lastRefresh_ = model->numberIterations(); } } return rhsOffset_; } /* update information for a pivot (and effective rhs) */ int ClpGubDynamicMatrix::updatePivot(ClpSimplex *model, double oldInValue, double oldOutValue) { // now update working model int sequenceIn = model->sequenceIn(); int sequenceOut = model->sequenceOut(); bool doPrinting = (model->messageHandler()->logLevel() == 63); bool print = false; int iSet; int trueIn = -1; int trueOut = -1; int numberRows = model->numberRows(); int numberColumns = model->numberColumns(); if (sequenceIn == firstAvailable_) { if (doPrinting) printf("New variable "); if (sequenceIn != sequenceOut) { insertNonBasic(firstAvailable_, backward_[firstAvailable_]); setDynamicStatus(id_[sequenceIn - firstDynamic_], inSmall); firstAvailable_++; } else { int bigSequence = id_[sequenceIn - firstDynamic_]; if (model->getStatus(sequenceIn) == ClpSimplex::atUpperBound) setDynamicStatus(bigSequence, atUpperBound); else setDynamicStatus(bigSequence, atLowerBound); } synchronize(model, 8); } if (sequenceIn < lastDynamic_) { iSet = backward_[sequenceIn]; if (iSet >= 0) { int bigSequence = id_[sequenceIn - firstDynamic_]; trueIn = bigSequence + numberRows + numberColumns + numberSets_; if (doPrinting) printf(" incoming set %d big seq %d", iSet, bigSequence); print = true; } } else if (sequenceIn >= numberRows + numberColumns) { trueIn = numberRows + numberColumns + gubSlackIn_; } if (sequenceOut < lastDynamic_) { iSet = backward_[sequenceOut]; if (iSet >= 0) { int bigSequence = id_[sequenceOut - firstDynamic_]; trueOut = bigSequence + firstDynamic_; if (getDynamicStatus(bigSequence) != inSmall) { if (model->getStatus(sequenceOut) == ClpSimplex::atUpperBound) setDynamicStatus(bigSequence, atUpperBound); else setDynamicStatus(bigSequence, atLowerBound); } if (doPrinting) printf(" ,outgoing set %d big seq %d,", iSet, bigSequence); print = true; model->setSequenceIn(sequenceOut); synchronize(model, 8); model->setSequenceIn(sequenceIn); } } if (print && doPrinting) printf("\n"); ClpGubMatrix::updatePivot(model, oldInValue, oldOutValue); // Redo true in and out if (trueIn >= 0) trueSequenceIn_ = trueIn; if (trueOut >= 0) trueSequenceOut_ = trueOut; if (doPrinting && 0) { for (int i = 0; i < numberSets_; i++) { printf("set %d key %d lower %g upper %g\n", i, keyVariable_[i], lower_[i], upper_[i]); for (int j = fullStart_[i]; j < fullStart_[i + 1]; j++) if (getDynamicStatus(j) == atUpperBound) { bool print = true; for (int k = firstDynamic_; k < firstAvailable_; k++) { if (id_[k - firstDynamic_] == j) print = false; if (id_[k - firstDynamic_] == j) assert(getDynamicStatus(j) == inSmall); } if (print) printf("variable %d at ub\n", j); } } } #ifdef CLP_DEBUG char *inSmall = new char[numberGubColumns_]; memset(inSmall, 0, numberGubColumns_); for (int i = 0; i < numberGubColumns_; i++) if (getDynamicStatus(i) == ClpGubDynamicMatrix::inSmall) inSmall[i] = 1; for (int i = firstDynamic_; i < firstAvailable_; i++) { int k = id_[i - firstDynamic_]; inSmall[k] = 0; } for (int i = 0; i < numberGubColumns_; i++) assert(!inSmall[i]); delete[] inSmall; #endif return 0; } void ClpGubDynamicMatrix::times(double scalar, const double *x, double *y) const { if (model_->specialOptions() != 16) { ClpPackedMatrix::times(scalar, x, y); } else { int iRow; int numberColumns = model_->numberColumns(); int numberRows = model_->numberRows(); const double *element = matrix_->getElements(); const int *row = matrix_->getIndices(); const CoinBigIndex *startColumn = matrix_->getVectorStarts(); const int *length = matrix_->getVectorLengths(); int *pivotVariable = model_->pivotVariable(); int numberToDo = 0; for (iRow = 0; iRow < numberRows; iRow++) { y[iRow] -= scalar * rhsOffset_[iRow]; int iColumn = pivotVariable[iRow]; if (iColumn < numberColumns) { int iSet = backward_[iColumn]; if (iSet >= 0 && toIndex_[iSet] < 0) { toIndex_[iSet] = 0; fromIndex_[numberToDo++] = iSet; } CoinBigIndex j; double value = scalar * x[iColumn]; if (value) { for (j = startColumn[iColumn]; j < startColumn[iColumn] + length[iColumn]; j++) { int jRow = row[j]; y[jRow] += value * element[j]; } } } } // and gubs which are interacting for (int jSet = 0; jSet < numberToDo; jSet++) { int iSet = fromIndex_[jSet]; toIndex_[iSet] = -1; int iKey = keyVariable_[iSet]; if (iKey < numberColumns) { double valueKey; if (getStatus(iSet) == ClpSimplex::atLowerBound) valueKey = lower_[iSet]; else valueKey = upper_[iSet]; double value = scalar * (x[iKey] - valueKey); if (value) { for (CoinBigIndex j = startColumn[iKey]; j < startColumn[iKey] + length[iKey]; j++) { int jRow = row[j]; y[jRow] += value * element[j]; } } } } } } /* Just for debug - may be extended to other matrix types later. Returns number and sum of primal infeasibilities. */ int ClpGubDynamicMatrix::checkFeasible(ClpSimplex * /*model*/, double &sum) const { int numberRows = model_->numberRows(); double *rhs = new double[numberRows]; int numberColumns = model_->numberColumns(); int iRow; CoinZeroN(rhs, numberRows); // do ones at bounds before gub const double *smallSolution = model_->solutionRegion(); const double *element = matrix_->getElements(); const int *row = matrix_->getIndices(); const CoinBigIndex *startColumn = matrix_->getVectorStarts(); const int *length = matrix_->getVectorLengths(); int iColumn; int numberInfeasible = 0; const double *rowLower = model_->rowLower(); const double *rowUpper = model_->rowUpper(); sum = 0.0; for (iRow = 0; iRow < numberRows; iRow++) { double value = smallSolution[numberColumns + iRow]; if (value < rowLower[iRow] - 1.0e-5 || value > rowUpper[iRow] + 1.0e-5) { //printf("row %d %g %g %g\n", // iRow,rowLower[iRow],value,rowUpper[iRow]); numberInfeasible++; sum += CoinMax(rowLower[iRow] - value, value - rowUpper[iRow]); } rhs[iRow] = value; } const double *columnLower = model_->columnLower(); const double *columnUpper = model_->columnUpper(); for (iColumn = 0; iColumn < firstDynamic_; iColumn++) { double value = smallSolution[iColumn]; if (value < columnLower[iColumn] - 1.0e-5 || value > columnUpper[iColumn] + 1.0e-5) { //printf("column %d %g %g %g\n", // iColumn,columnLower[iColumn],value,columnUpper[iColumn]); numberInfeasible++; sum += CoinMax(columnLower[iColumn] - value, value - columnUpper[iColumn]); } for (CoinBigIndex j = startColumn[iColumn]; j < startColumn[iColumn] + length[iColumn]; j++) { int jRow = row[j]; rhs[jRow] -= value * element[j]; } } double *solution = new double[numberGubColumns_]; for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) { double value = 0.0; if (getDynamicStatus(iColumn) == atUpperBound) value = upperColumn_[iColumn]; else if (lowerColumn_) value = lowerColumn_[iColumn]; solution[iColumn] = value; } // ones in small and gub for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) { int jFull = id_[iColumn - firstDynamic_]; solution[jFull] = smallSolution[iColumn]; } // fill in all basic in small model int *pivotVariable = model_->pivotVariable(); for (iRow = 0; iRow < numberRows; iRow++) { int iColumn = pivotVariable[iRow]; if (iColumn >= firstDynamic_ && iColumn < lastDynamic_) { int iSequence = id_[iColumn - firstDynamic_]; solution[iSequence] = smallSolution[iColumn]; } } // and now compute value to use for key ClpSimplex::Status iStatus; for (int iSet = 0; iSet < numberSets_; iSet++) { iColumn = keyVariable_[iSet]; if (iColumn < numberColumns) { int iSequence = id_[iColumn - firstDynamic_]; solution[iSequence] = 0.0; double b = 0.0; // key is structural - where is slack iStatus = getStatus(iSet); assert(iStatus != ClpSimplex::basic); if (iStatus == ClpSimplex::atLowerBound) b = lower_[iSet]; else b = upper_[iSet]; // subtract out others at bounds for (int j = fullStart_[iSet]; j < fullStart_[iSet + 1]; j++) b -= solution[j]; solution[iSequence] = b; } } for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) { double value = solution[iColumn]; if ((lowerColumn_ && value < lowerColumn_[iColumn] - 1.0e-5) || (!lowerColumn_ && value < -1.0e-5) || (upperColumn_ && value > upperColumn_[iColumn] + 1.0e-5)) { //printf("column %d %g %g %g\n", // iColumn,lowerColumn_[iColumn],value,upperColumn_[iColumn]); numberInfeasible++; } if (value) { for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn + 1]; j++) { int iRow = row_[j]; rhs[iRow] -= element_[j] * value; } } } for (iRow = 0; iRow < numberRows; iRow++) { if (fabs(rhs[iRow]) > 1.0e-5) printf("rhs mismatch %d %g\n", iRow, rhs[iRow]); } delete[] solution; delete[] rhs; return numberInfeasible; } // Cleans data after setWarmStart void ClpGubDynamicMatrix::cleanData(ClpSimplex *model) { // and redo chains int numberColumns = model->numberColumns(); int iColumn; // do backward int *mark = new int[numberGubColumns_]; for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) mark[iColumn] = -1; int i; for (i = 0; i < firstDynamic_; i++) { assert(backward_[i] == -1); next_[i] = -1; } for (i = firstDynamic_; i < firstAvailable_; i++) { iColumn = id_[i - firstDynamic_]; mark[iColumn] = i; } for (i = 0; i < numberSets_; i++) { int iKey = keyVariable_[i]; int lastNext = -1; int firstNext = -1; for (CoinBigIndex k = fullStart_[i]; k < fullStart_[i + 1]; k++) { iColumn = mark[k]; if (iColumn >= 0) { if (iColumn != iKey) { if (lastNext >= 0) next_[lastNext] = iColumn; else firstNext = iColumn; lastNext = iColumn; } backward_[iColumn] = i; } } setFeasible(i); if (firstNext >= 0) { // others next_[iKey] = firstNext; next_[lastNext] = -(iKey + 1); } else if (iKey < numberColumns) { next_[iKey] = -(iKey + 1); } } delete[] mark; // fill matrix double *element = matrix_->getMutableElements(); int *row = matrix_->getMutableIndices(); CoinBigIndex *startColumn = matrix_->getMutableVectorStarts(); int *length = matrix_->getMutableVectorLengths(); CoinBigIndex numberElements = startColumn[firstDynamic_]; for (i = firstDynamic_; i < firstAvailable_; i++) { int iColumn = id_[i - firstDynamic_]; int numberThis = startColumn_[iColumn + 1] - startColumn_[iColumn]; length[i] = numberThis; for (CoinBigIndex jBigIndex = startColumn_[iColumn]; jBigIndex < startColumn_[iColumn + 1]; jBigIndex++) { row[numberElements] = row_[jBigIndex]; element[numberElements++] = element_[jBigIndex]; } startColumn[i + 1] = numberElements; } } /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2 */