/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* This file is part of the class library */ /* SoPlex --- the Sequential object-oriented simPlex. */ /* */ /* Copyright 1996-2022 Zuse Institute Berlin */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ /* See the License for the specific language governing permissions and */ /* limitations under the License. */ /* */ /* You should have received a copy of the Apache-2.0 license */ /* along with SoPlex; see the file LICENSE. If not email to soplex@zib.de. */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "soplex/spxdefines.h" #include "soplex/spxsolver.h" #include "soplex/spxpricer.h" #include "soplex/spxratiotester.h" #include "soplex/exceptions.h" namespace soplex { template void SPxSolverBase::addedRows(int n) { if(n > 0) { SPxLPBase::addedRows(n); unInit(); reDim(); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) SPxBasisBase::addedRows(n); } /* we must not assert consistency here, since addedCols() might be still necessary to obtain a consistent basis */ } template void SPxSolverBase::addedCols(int n) { if(n > 0) { SPxLPBase::addedCols(n); unInit(); reDim(); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) SPxBasisBase::addedCols(n); } /* we must not assert consistency here, since addedRows() might be still necessary to obtain a consistent basis */ } template void SPxSolverBase::doRemoveRow(int i) { SPxLPBase::doRemoveRow(i); unInit(); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { this->removedRow(i); switch(SPxBasisBase::status()) { case SPxBasisBase::DUAL: case SPxBasisBase::INFEASIBLE: setBasisStatus(SPxBasisBase::REGULAR); break; case SPxBasisBase::OPTIMAL: setBasisStatus(SPxBasisBase::PRIMAL); break; default: break; } } } template void SPxSolverBase::doRemoveRows(int perm[]) { SPxLPBase::doRemoveRows(perm); unInit(); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { this->removedRows(perm); switch(SPxBasisBase::status()) { case SPxBasisBase::DUAL: case SPxBasisBase::INFEASIBLE: setBasisStatus(SPxBasisBase::REGULAR); break; case SPxBasisBase::OPTIMAL: setBasisStatus(SPxBasisBase::PRIMAL); break; default: break; } } } template void SPxSolverBase::doRemoveCol(int i) { forceRecompNonbasicValue(); SPxLPBase::doRemoveCol(i); unInit(); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { this->removedCol(i); switch(SPxBasisBase::status()) { case SPxBasisBase::PRIMAL: case SPxBasisBase::UNBOUNDED: setBasisStatus(SPxBasisBase::REGULAR); break; case SPxBasisBase::OPTIMAL: setBasisStatus(SPxBasisBase::DUAL); break; default: break; } } } template void SPxSolverBase::doRemoveCols(int perm[]) { forceRecompNonbasicValue(); SPxLPBase::doRemoveCols(perm); unInit(); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { this->removedCols(perm); switch(SPxBasisBase::status()) { case SPxBasisBase::PRIMAL: case SPxBasisBase::UNBOUNDED: setBasisStatus(SPxBasisBase::REGULAR); break; case SPxBasisBase::OPTIMAL: setBasisStatus(SPxBasisBase::DUAL); break; default: break; } } } template void SPxSolverBase::changeObj(const VectorBase& newObj, bool scale) { forceRecompNonbasicValue(); SPxLPBase::changeObj(newObj, scale); /**@todo Factorization remains valid, we do not need a reDim() * pricing vectors should be recomputed. */ unInit(); } template void SPxSolverBase::changeObj(int i, const R& newVal, bool scale) { forceRecompNonbasicValue(); SPxLPBase::changeObj(i, newVal, scale); /**@todo Factorization remains valid, we do not need a reDim() * pricing vectors should be recomputed. */ unInit(); } template void SPxSolverBase::changeMaxObj(const VectorBase& newObj, bool scale) { forceRecompNonbasicValue(); SPxLPBase::changeMaxObj(newObj, scale); /**@todo Factorization remains valid, we do not need a reDim() * pricing vectors should be recomputed. */ unInit(); } template void SPxSolverBase::changeMaxObj(int i, const R& newVal, bool scale) { forceRecompNonbasicValue(); SPxLPBase::changeMaxObj(i, newVal, scale); /**@todo Factorization remains valid, we do not need a reDim() * pricing vectors should be recomputed. */ unInit(); } template void SPxSolverBase::changeRowObj(const VectorBase& newObj, bool scale) { forceRecompNonbasicValue(); SPxLPBase::changeRowObj(newObj, scale); /**@todo Factorization remains valid, we do not need a reDim() * pricing vectors should be recomputed. */ unInit(); } template void SPxSolverBase::changeRowObj(int i, const R& newVal, bool scale) { forceRecompNonbasicValue(); SPxLPBase::changeRowObj(i, newVal, scale); /**@todo Factorization remains valid, we do not need a reDim() * pricing vectors should be recomputed. */ unInit(); } template void SPxSolverBase::changeLowerStatus(int i, R newLower, R oldLower) { typename SPxBasisBase::Desc::Status& stat = this->desc().colStatus(i); R currUpper = this->upper(i); R objChange = 0.0; MSG_DEBUG(std::cout << "DCHANG01 changeLowerStatus(): col " << i << "[" << newLower << ":" << currUpper << "] " << stat;) switch(stat) { case SPxBasisBase::Desc::P_ON_LOWER: if(newLower <= R(-infinity)) { if(currUpper >= R(infinity)) { stat = SPxBasisBase::Desc::P_FREE; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = -theLCbound[i] * oldLower; } else { stat = SPxBasisBase::Desc::P_ON_UPPER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = (theUCbound[i] * currUpper) - (theLCbound[i] * oldLower); } } else if(EQ(newLower, currUpper)) { stat = SPxBasisBase::Desc::P_FIXED; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = this->maxObj(i) * (newLower - oldLower); } else if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theLCbound[i] * (newLower - oldLower); break; case SPxBasisBase::Desc::P_ON_UPPER: if(EQ(newLower, currUpper)) stat = SPxBasisBase::Desc::P_FIXED; break; case SPxBasisBase::Desc::P_FREE: if(newLower > R(-infinity)) { stat = SPxBasisBase::Desc::P_ON_LOWER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theLCbound[i] * newLower; } break; case SPxBasisBase::Desc::P_FIXED: if(NE(newLower, currUpper)) { stat = SPxBasisBase::Desc::P_ON_UPPER; if(isInitialized()) theUCbound[i] = this->maxObj(i); } break; case SPxBasisBase::Desc::D_FREE: case SPxBasisBase::Desc::D_ON_UPPER: case SPxBasisBase::Desc::D_ON_LOWER: case SPxBasisBase::Desc::D_ON_BOTH: case SPxBasisBase::Desc::D_UNDEFINED: if(rep() == ROW && theShift > 0.0) forceRecompNonbasicValue(); stat = this->dualColStatus(i); break; default: throw SPxInternalCodeException("XCHANG01 This should never happen."); } MSG_DEBUG(std::cout << " -> " << stat << std::endl;) // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation) if(rep() == COLUMN) updateNonbasicValue(objChange); } template void SPxSolverBase::changeLower(const VectorBase& newLower, bool scale) { // we better recompute the nonbasic value when changing all lower bounds forceRecompNonbasicValue(); SPxLPBase::changeLower(newLower, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { for(int i = 0; i < newLower.dim(); ++i) changeLowerStatus(i, this->lower(i)); unInit(); } } template void SPxSolverBase::changeLower(int i, const R& newLower, bool scale) { if(newLower != (scale ? this->lowerUnscaled(i) : this->lower(i))) { forceRecompNonbasicValue(); R oldLower = this->lower(i); // This has to be done before calling changeLowerStatus() because that is calling // basis.dualColStatus() which calls lower() and needs the changed value. SPxLPBase::changeLower(i, newLower, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { changeLowerStatus(i, this->lower(i), oldLower); unInit(); } } } template void SPxSolverBase::changeUpperStatus(int i, R newUpper, R oldUpper) { typename SPxBasisBase::Desc::Status& stat = this->desc().colStatus(i); R currLower = this->lower(i); R objChange = 0.0; MSG_DEBUG(std::cout << "DCHANG02 changeUpperStatus(): col " << i << "[" << currLower << ":" << newUpper << "] " << stat;) switch(stat) { case SPxBasisBase::Desc::P_ON_LOWER: if(newUpper == currLower) stat = SPxBasisBase::Desc::P_FIXED; break; case SPxBasisBase::Desc::P_ON_UPPER: if(newUpper >= R(infinity)) { if(currLower <= R(-infinity)) { stat = SPxBasisBase::Desc::P_FREE; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = -theUCbound[i] * oldUpper; } else { stat = SPxBasisBase::Desc::P_ON_LOWER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = (theLCbound[i] * currLower) - (theUCbound[i] * oldUpper); } } else if(EQ(newUpper, currLower)) { stat = SPxBasisBase::Desc::P_FIXED; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = this->maxObj(i) * (newUpper - oldUpper); } else if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theUCbound[i] * (newUpper - oldUpper); break; case SPxBasisBase::Desc::P_FREE: if(newUpper < R(infinity)) { stat = SPxBasisBase::Desc::P_ON_UPPER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theUCbound[i] * newUpper; } break; case SPxBasisBase::Desc::P_FIXED: if(NE(newUpper, currLower)) { stat = SPxBasisBase::Desc::P_ON_LOWER; if(isInitialized()) theLCbound[i] = this->maxObj(i); } break; case SPxBasisBase::Desc::D_FREE: case SPxBasisBase::Desc::D_ON_UPPER: case SPxBasisBase::Desc::D_ON_LOWER: case SPxBasisBase::Desc::D_ON_BOTH: case SPxBasisBase::Desc::D_UNDEFINED: if(rep() == ROW && theShift > 0.0) forceRecompNonbasicValue(); stat = this->dualColStatus(i); break; default: throw SPxInternalCodeException("XCHANG02 This should never happen."); } MSG_DEBUG(std::cout << " -> " << stat << std::endl;); // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation) if(rep() == COLUMN) updateNonbasicValue(objChange); } template void SPxSolverBase::changeUpper(const VectorBase& newUpper, bool scale) { // we better recompute the nonbasic value when changing all upper bounds forceRecompNonbasicValue(); SPxLPBase::changeUpper(newUpper, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { for(int i = 0; i < newUpper.dim(); ++i) changeUpperStatus(i, this->upper(i)); unInit(); } } template void SPxSolverBase::changeUpper(int i, const R& newUpper, bool scale) { if(newUpper != (scale ? this->upperUnscaled(i) : this->upper(i))) { forceRecompNonbasicValue(); R oldUpper = this->upper(i); SPxLPBase::changeUpper(i, newUpper, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { changeUpperStatus(i, this->upper(i), oldUpper); unInit(); } } } template void SPxSolverBase::changeBounds(const VectorBase& newLower, const VectorBase& newUpper, bool scale) { changeLower(newLower, scale); changeUpper(newUpper, scale); } template void SPxSolverBase::changeBounds(int i, const R& newLower, const R& newUpper, bool scale) { changeLower(i, newLower, scale); if(EQ(newLower, newUpper)) changeUpper(i, newLower, scale); else changeUpper(i, newUpper, scale); } template void SPxSolverBase::changeLhsStatus(int i, R newLhs, R oldLhs) { typename SPxBasisBase::Desc::Status& stat = this->desc().rowStatus(i); R currRhs = this->rhs(i); R objChange = 0.0; MSG_DEBUG(std::cout << "DCHANG03 changeLhsStatus() : row " << i << ": " << stat;) switch(stat) { case SPxBasisBase::Desc::P_ON_LOWER: if(newLhs <= R(-infinity)) { if(currRhs >= R(infinity)) { stat = SPxBasisBase::Desc::P_FREE; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = -theURbound[i] * oldLhs; } else { stat = SPxBasisBase::Desc::P_ON_UPPER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = (theLRbound[i] * currRhs) - (theURbound[i] * oldLhs); } } else if(EQ(newLhs, currRhs)) { stat = SPxBasisBase::Desc::P_FIXED; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = this->maxRowObj(i) * (newLhs - oldLhs); } else if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theURbound[i] * (newLhs - oldLhs); break; case SPxBasisBase::Desc::P_ON_UPPER: if(EQ(newLhs, currRhs)) stat = SPxBasisBase::Desc::P_FIXED; break; case SPxBasisBase::Desc::P_FREE: if(newLhs > R(-infinity)) { stat = SPxBasisBase::Desc::P_ON_LOWER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theURbound[i] * newLhs; } break; case SPxBasisBase::Desc::P_FIXED: if(NE(newLhs, currRhs)) { stat = SPxBasisBase::Desc::P_ON_UPPER; if(isInitialized()) theLRbound[i] = this->maxRowObj(i); } break; case SPxBasisBase::Desc::D_FREE: case SPxBasisBase::Desc::D_ON_UPPER: case SPxBasisBase::Desc::D_ON_LOWER: case SPxBasisBase::Desc::D_ON_BOTH: case SPxBasisBase::Desc::D_UNDEFINED: if(rep() == ROW && theShift > 0.0) forceRecompNonbasicValue(); stat = this->dualRowStatus(i); break; default: throw SPxInternalCodeException("XCHANG03 This should never happen."); } MSG_DEBUG(std::cout << " -> " << stat << std::endl;) // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation) if(rep() == COLUMN) updateNonbasicValue(objChange); } template void SPxSolverBase::changeLhs(const VectorBase& newLhs, bool scale) { // we better recompute the nonbasic value when changing all lhs forceRecompNonbasicValue(); SPxLPBase::changeLhs(newLhs, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { for(int i = 0; i < this->nRows(); ++i) changeLhsStatus(i, this->lhs(i)); unInit(); } } template void SPxSolverBase::changeLhs(int i, const R& newLhs, bool scale) { if(newLhs != (scale ? this->lhsUnscaled(i) : this->lhs(i))) { forceRecompNonbasicValue(); R oldLhs = this->lhs(i); SPxLPBase::changeLhs(i, newLhs, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { changeLhsStatus(i, this->lhs(i), oldLhs); unInit(); } } } template void SPxSolverBase::changeRhsStatus(int i, R newRhs, R oldRhs) { typename SPxBasisBase::Desc::Status& stat = this->desc().rowStatus(i); R currLhs = this->lhs(i); R objChange = 0.0; MSG_DEBUG(std::cout << "DCHANG04 changeRhsStatus() : row " << i << ": " << stat;) switch(stat) { case SPxBasisBase::Desc::P_ON_UPPER: if(newRhs >= R(infinity)) { if(currLhs <= R(-infinity)) { stat = SPxBasisBase::Desc::P_FREE; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = -theLRbound[i] * oldRhs; } else { stat = SPxBasisBase::Desc::P_ON_LOWER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = (theURbound[i] * currLhs) - (theLRbound[i] * oldRhs); } } else if(EQ(newRhs, currLhs)) { stat = SPxBasisBase::Desc::P_FIXED; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = this->maxRowObj(i) * (newRhs - oldRhs); } else if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theLRbound[i] * (newRhs - oldRhs); break; case SPxBasisBase::Desc::P_ON_LOWER: if(EQ(newRhs, currLhs)) stat = SPxBasisBase::Desc::P_FIXED; break; case SPxBasisBase::Desc::P_FREE: if(newRhs < R(infinity)) { stat = SPxBasisBase::Desc::P_ON_UPPER; if(m_nonbasicValueUpToDate && rep() == COLUMN) objChange = theLRbound[i] * newRhs; } break; case SPxBasisBase::Desc::P_FIXED: if(NE(newRhs, currLhs)) { stat = SPxBasisBase::Desc::P_ON_LOWER; if(isInitialized()) theURbound[i] = this->maxRowObj(i); } break; case SPxBasisBase::Desc::D_FREE: case SPxBasisBase::Desc::D_ON_UPPER: case SPxBasisBase::Desc::D_ON_LOWER: case SPxBasisBase::Desc::D_ON_BOTH: case SPxBasisBase::Desc::D_UNDEFINED: if(rep() == ROW && theShift > 0.0) forceRecompNonbasicValue(); stat = this->dualRowStatus(i); break; default: throw SPxInternalCodeException("XCHANG04 This should never happen."); } MSG_DEBUG(std::cout << " -> " << stat << std::endl;) // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation) if(rep() == COLUMN) updateNonbasicValue(objChange); } template void SPxSolverBase::changeRhs(const VectorBase& newRhs, bool scale) { // we better recompute the nonbasic value when changing all rhs forceRecompNonbasicValue(); SPxLPBase::changeRhs(newRhs, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { for(int i = 0; i < this->nRows(); ++i) changeRhsStatus(i, this->rhs(i)); unInit(); } } template void SPxSolverBase::changeRhs(int i, const R& newRhs, bool scale) { if(newRhs != (scale ? this->rhsUnscaled(i) : this->rhs(i))) { forceRecompNonbasicValue(); R oldRhs = this->rhs(i); SPxLPBase::changeRhs(i, newRhs, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { changeRhsStatus(i, this->rhs(i), oldRhs); unInit(); } } } template void SPxSolverBase::changeRange(const VectorBase& newLhs, const VectorBase& newRhs, bool scale) { // we better recompute the nonbasic value when changing all ranges forceRecompNonbasicValue(); SPxLPBase::changeLhs(newLhs, scale); SPxLPBase::changeRhs(newRhs, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { for(int i = this->nRows() - 1; i >= 0; --i) { changeLhsStatus(i, this->lhs(i)); changeRhsStatus(i, this->rhs(i)); } unInit(); } } template void SPxSolverBase::changeRange(int i, const R& newLhs, const R& newRhs, bool scale) { R oldLhs = this->lhs(i); R oldRhs = this->rhs(i); SPxLPBase::changeLhs(i, newLhs, scale); if(EQ(newLhs, newRhs)) SPxLPBase::changeRhs(i, newLhs, scale); else SPxLPBase::changeRhs(i, newRhs, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) { changeLhsStatus(i, this->lhs(i), oldLhs); changeRhsStatus(i, this->rhs(i), oldRhs); unInit(); } } template void SPxSolverBase::changeRow(int i, const LPRowBase& newRow, bool scale) { forceRecompNonbasicValue(); SPxLPBase::changeRow(i, newRow, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) SPxBasisBase::changedRow(i); unInit(); } template void SPxSolverBase::changeCol(int i, const LPColBase& newCol, bool scale) { if(i < 0) return; forceRecompNonbasicValue(); SPxLPBase::changeCol(i, newCol, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) SPxBasisBase::changedCol(i); unInit(); } template void SPxSolverBase::changeElement(int i, int j, const R& val, bool scale) { if(i < 0 || j < 0) return; forceRecompNonbasicValue(); SPxLPBase::changeElement(i, j, val, scale); if(SPxBasisBase::status() > SPxBasisBase::NO_PROBLEM) SPxBasisBase::changedElement(i, j); unInit(); } template void SPxSolverBase::changeSense(typename SPxLPBase::SPxSense sns) { SPxLPBase::changeSense(sns); unInit(); } } // namespace soplex