/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* 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. */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /**@file lprowsetbase.h * @brief Set of LP columns. */ #ifndef _LPROWSETBASE_H_ #define _LPROWSETBASE_H_ #include #include "soplex/spxdefines.h" #include "soplex/basevectors.h" #include "soplex/datakey.h" #include "soplex/lprowbase.h" namespace soplex { /**@brief Set of LP rows. * @ingroup Algebra * * Class LPRowSetBase implements a set of \ref LPRowBase "LPRowBase%s". Unless for memory limitations, any number of * LPRowBase%s may be #add%ed to an LPRowSetBase. Single or multiple LPRowBase%s may be added to an LPRowSetBase, where * each method add() comes with two different signatures. One with and one without a parameter, used for returning the * Keys assigned to the new LPRowBase%s by the set. See DataKey for a more detailed description of the concept of * keys. For the concept of renumbering LPRowBase%s within an LPRowSetBase after removal of some LPRows see DataSet. * * @see DataSet, DataKey */ template < class R > class LPRowSetBase : protected SVSetBase { template < class S > friend class LPRowSetBase; private: // ------------------------------------------------------------------------------------------------------------------ /**@name Data */ ///@{ VectorBase left; ///< vector of left hand sides (lower bounds) of LPRowBase%s. VectorBase right; ///< vector of right hand sides (upper bounds) of LPRowBase%s. VectorBase object; ///< vector of objective coefficients. ///@} protected: DataArray < int > scaleExp; ///< row scaling factors (stored as bitshift) // ------------------------------------------------------------------------------------------------------------------ /**@name Helpers */ ///@{ /// Returns the complete SVSet. const SVSetBase* rowSet() const { return this; } ///@} public: // ------------------------------------------------------------------------------------------------------------------ /**@name Access / modification */ ///@{ /// Returns the number of LPRowBase%s in LPRowSetBase. int num() const { return SVSetBase::num(); } /// Returns the maximum number of LPRowBase%s that fit. int max() const { return SVSetBase::max(); } /// Returns the vector of lhs values. const VectorBase& lhs() const { return left; } /// Returns the vector of lhs values. VectorBase& lhs_w() { return left; } /// Returns the lhs of the \p i 'th LPRowBase. const R& lhs(int i) const { return left[i]; } /// Returns the lhs of the \p i 'th LPRowBase. R& lhs_w(int i) { return left[i]; } /// Returns the lhs of the LPRowBase with DataKey \p k in LPRowSetBase. const R& lhs(const DataKey& k) const { return left[number(k)]; } /// Returns the lhs of the LPRowBase with DataKey \p k in LPRowSetBase. R& lhs_w(const DataKey& k) { return left[number(k)]; } /// Returns the vector of rhs values. const VectorBase& rhs() const { return right; } /// Returns the vector of rhs values (writeable). VectorBase& rhs_w() { return right; } /// Returns the rhs of the \p i 'th LPRowBase. const R& rhs(int i) const { return right[i]; } /// Returns the rhs of the \p i 'th LPRowBase (writeable). R& rhs_w(int i) { return right[i]; } /// Returns the rhs of the LPRowBase with DataKey \p k in LPRowSetBase. const R& rhs(const DataKey& k) const { return right[number(k)]; } /// Returns the rhs of the LPRowBase with DataKey \p k in LPRowSetBase (writeable). R& rhs_w(const DataKey& k) { return right[number(k)]; } /// Returns the vector of objective coefficients. const VectorBase& obj() const { return object; } /// Returns the vector of objective coefficients (writeable). VectorBase& obj_w() { return object; } /// Returns the objective coefficient of the \p i 'th LPRowBase. const R& obj(int i) const { return object[i]; } /// Returns the objective coefficient of the \p i 'th LPRowBase (writeable). R& obj_w(int i) { return object[i]; } /// Returns the objective coefficient of the LPRowBase with DataKey \p k in LPRowSetBase. const R& obj(const DataKey& k) const { return object[number(k)]; } /// Returns the objective coefficient of the LPRowBase with DataKey \p k in LPRowSetBase (writeable). R& obj_w(const DataKey& k) { return object[number(k)]; } /// Returns a writable rowVector of the \p i 'th LPRowBase. SVectorBase& rowVector_w(int i) { return SVSetBase::operator[](i); } /// Returns the rowVector of the \p i 'th LPRowBase. const SVectorBase& rowVector(int i) const { return SVSetBase::operator[](i); } /// Returns a writable rowVector of the LPRowBase with DataKey \p k. SVectorBase& rowVector_w(const DataKey& k) { return SVSetBase::operator[](k); } /// Returns the rowVector of the LPRowBase with DataKey \p k. const SVectorBase& rowVector(const DataKey& k) const { return SVSetBase::operator[](k); } /// Returns the inequalitiy type of the \p i 'th LPRowBase. typename LPRowBase::Type type(int i) const { if(rhs(i) >= R(infinity)) return LPRowBase::GREATER_EQUAL; if(lhs(i) <= R(-infinity)) return LPRowBase::LESS_EQUAL; if(lhs(i) == rhs(i)) return LPRowBase::EQUAL; return LPRowBase::RANGE; } /// Returns the inequality type of the LPRowBase with DataKey \p k. typename LPRowBase::Type type(const DataKey& k) const { return type(number(k)); } /// Changes the inequality type of row \p i to \p type. void setType(int i, typename LPRowBase::Type t) { switch(t) { case LPRowBase::LESS_EQUAL: lhs_w(i) = R(-infinity); break; case LPRowBase::EQUAL: if(lhs_w(i) > R(-infinity)) rhs_w(i) = lhs(i); else lhs_w(i) = rhs(i); break; case LPRowBase::GREATER_EQUAL: rhs_w(i) = R(infinity); break; case LPRowBase::RANGE: MSG_ERROR(std::cerr << "EROWST01 RANGE not supported in LPRowSet::setType()" << std::endl); throw SPxInternalCodeException("XROWST01 This should never happen."); default: throw SPxInternalCodeException("XROWST02 This should never happen."); } } /// Returns the value of the \p i'th LPRowBase. const R& value(int i) const { if(rhs(i) < R(infinity)) return rhs(i); else { assert(lhs(i) > R(-infinity)); return lhs(i); } } /// Returns the value of the LPRowBase with DataKey \p k. /** The \em value of a row depends on its type: if the inequality is of type "greater or equal", the value is the lhs * of the row. Otherwise, the value is the rhs. */ const R& value(const DataKey& k) const { return value(number(k)); } /// Returns the DataKey of the \p i 'th LPRowBase in LPRowSetBase. DataKey key(int i) const { return SVSetBase::key(i); } /// Returns the number of the LPRowBase with DataKey \p k in LPRowSetBase. int number(const DataKey& k) const { return SVSetBase::number(k); } /// does DataKey \p k belong to LPRowSetBase ? bool has(const DataKey& k) const { return SVSetBase::has(k); } ///@} // ------------------------------------------------------------------------------------------------------------------ /**@name Extension * * Extension methods come with two signatures, one of them providing a parameter to return the assigned * DataKey(s). See DataSet for a more detailed description. All extension methods will automatically rearrange or * allocate more memory if required. */ ///@{ /// void add(const LPRowBase& row) { DataKey k; add(k, row); } /// Adds \p row to LPRowSetBase. void add(DataKey& pkey, const LPRowBase& prow) { add(pkey, prow.lhs(), prow.rowVector(), prow.rhs(), prow.obj()); } /// Adds LPRowBase consisting of left hand side \p lhs, row vector \p rowVector, and right hand side \p rhs to LPRowSetBase. void add(const R& plhs, const SVectorBase& prowVector, const R& prhs, const R& pobj = 0, const int& pscaleExp = 0) { DataKey k; add(k, plhs, prowVector, prhs, pobj, pscaleExp); } /// Adds LPRowBase consisting of left hand side \p lhs, row vector \p rowVector, and right hand side \p rhs to LPRowSetBase. template < class S > void add(const S* lhsValue, const S* rowValues, const int* rowIndices, int rowSize, const S* rhsValue, const S* objValue = 0) { assert(lhsValue != 0); assert(rowSize <= 0 || rowValues != 0); assert(rowSize <= 0 || rowIndices != 0); assert(rhsValue != 0); DataKey k; add(k, lhsValue, rowValues, rowIndices, rowSize, rhsValue, objValue); } /// Adds LPRowBase consisting of left hand side \p lhs, row vector \p rowVector, and right hand side \p rhs to /// LPRowSetBase, with DataKey \p key. template < class S > void add(DataKey& newkey, const S* lhsValue, const S* rowValues, const int* rowIndices, int rowSize, const S* rhsValue, const S* objValue = 0) { assert(lhsValue != 0); assert(rowSize <= 0 || rowValues != 0); assert(rowSize <= 0 || rowIndices != 0); assert(rhsValue != 0); SVSetBase::add(newkey, rowValues, rowIndices, rowSize); if(num() > left.dim()) { left.reDim(num()); right.reDim(num()); object.reDim(num()); } left[num() - 1] = *lhsValue; right[num() - 1] = *rhsValue; if(objValue != 0) object[num() - 1] = *objValue; else object[num() - 1] = 0; } /// Adds LPRowBase consisting of left hand side \p lhs, row vector \p rowVector, and right hand side \p rhs to /// LPRowSetBase, with DataKey \p key. void add(DataKey& newkey, const R& newlhs, const SVectorBase& newrowVector, const R& newrhs, const R& newobj = 0, const int& newscaleExp = 0) { SVSetBase::add(newkey, newrowVector); if(num() > left.dim()) { left.reDim(num()); right.reDim(num()); object.reDim(num()); scaleExp.reSize(num()); } left[num() - 1] = newlhs; right[num() - 1] = newrhs; object[num() - 1] = newobj; scaleExp[num() - 1] = newscaleExp; } /// void add(const LPRowSetBase& newset) { int i = num(); SVSetBase::add(newset); if(num() > left.dim()) { left.reDim(num()); right.reDim(num()); object.reDim(num()); scaleExp.reSize(num()); } for(int j = 0; i < num(); ++i, ++j) { left[i] = newset.lhs(j); right[i] = newset.rhs(j); object[i] = newset.obj(j); scaleExp[i] = newset.scaleExp[j]; } } /// Adds all LPRowBase%s of \p set to LPRowSetBase. void add(DataKey keys[], const LPRowSetBase& set) { int i = num(); add(set); for(int j = 0; i < num(); ++i, ++j) keys[j] = key(i); } /// Extends row \p n to fit \p newmax nonzeros. void xtend(int n, int newmax) { SVSetBase::xtend(rowVector_w(n), newmax); } /// Extends row with DataKey \p key to fit \p newmax nonzeros. void xtend(const DataKey& pkey, int pnewmax) { SVSetBase::xtend(rowVector_w(pkey), pnewmax); } /// Adds \p n nonzero (\p idx, \p val)-pairs to rowVector with DataKey \p k. void add2(const DataKey& k, int n, const int idx[], const R val[]) { SVSetBase::add2(rowVector_w(k), n, idx, val); } /// Adds \p n nonzero (\p idx, \p val)-pairs to \p i 'th rowVector. void add2(int i, int n, const int idx[], const R val[]) { SVSetBase::add2(rowVector_w(i), n, idx, val); } /// Adds \p n nonzero (\p idx, \p val)-pairs to \p i 'th rowVector. template < class S > void add2(int i, int n, const int idx[], const S val[]) { SVSetBase::add2(rowVector_w(i), n, idx, val); } /// Creates new LPRowBase with specified parameters and returns a reference to its row vector. SVectorBase& create(int pnonzeros = 0, const R& plhs = 0, const R& prhs = 1, const R& pobj = 0, const int& pscaleExp = 0) { DataKey k; return create(k, pnonzeros, plhs, prhs, pobj, pscaleExp); } /// Creates new LPRowBase with specified parameters and returns a reference to its row vector. SVectorBase& create(DataKey& newkey, int nonzeros = 0, const R& newlhs = 0, const R& newrhs = 1, const R& newobj = 0, const int& newscaleExp = 0) { if(num() + 1 > left.dim()) { left.reDim(num() + 1); right.reDim(num() + 1); object.reDim(num() + 1); scaleExp.reSize(num() + 1); } left[num()] = newlhs; right[num()] = newrhs; object[num()] = newobj; scaleExp[num()] = newscaleExp; return *SVSetBase::create(newkey, nonzeros); } ///@} // ------------------------------------------------------------------------------------------------------------------ /**@name Shrinking * * See DataSet for a description of the renumbering of the remaining LPRowBase%s in a LPRowSetBase after the call of * a removal method. */ ///@{ /// Removes \p i 'th LPRowBase. void remove(int i) { SVSetBase::remove(i); left[i] = left[num()]; right[i] = right[num()]; object[i] = object[num()]; scaleExp[i] = scaleExp[num()]; left.reDim(num()); right.reDim(num()); object.reDim(num()); scaleExp.reSize(num()); } /// Removes LPRowBase with DataKey \p k. void remove(const DataKey& k) { remove(number(k)); } /// Removes multiple LPRowBase%s. void remove(int perm[]) { int j = num(); SVSetBase::remove(perm); for(int i = 0; i < j; ++i) { if(perm[i] >= 0 && perm[i] != i) { left[perm[i]] = left[i]; right[perm[i]] = right[i]; object[perm[i]] = object[i]; scaleExp[perm[i]] = scaleExp[i]; } } left.reDim(num()); right.reDim(num()); object.reDim(num()); scaleExp.reSize(num()); } /// Removes \p n LPRowBase%s with row numbers given by \p nums. void remove(const int nums[], int n) { DataArray perm(num()); remove(nums, n, perm.get_ptr()); } /// Removes \p n LPRowBase%s with row numbers given by \p nums, /// Stores permutation of row indices in \p perm. void remove(const int nums[], int n, int* perm) { SVSetBase::remove(nums, n, perm); int j = num(); for(int i = 0; i < j; ++i) { if(perm[i] >= 0 && perm[i] != i) { left[perm[i]] = left[i]; right[perm[i]] = right[i]; object[perm[i]] = object[i]; scaleExp[perm[i]] = scaleExp[i]; } } left.reDim(num()); right.reDim(num()); object.reDim(num()); scaleExp.reSize(num()); } /// Removes all LPRowBase%s. void clear() { SVSetBase::clear(); left.reDim(num()); right.reDim(num()); object.reDim(num()); scaleExp.clear(); } ///@} // ------------------------------------------------------------------------------------------------------------------ /**@name Memory Management * * For a description of the memory management methods, see the documentation of SVSet, which has been used for * implementating LPRowSetBase. */ ///@{ /// Reallocates memory to be able to store \p newmax LPRowBase%s. void reMax(int newmax = 0) { SVSetBase::reMax(newmax); left.reSize(max()); right.reSize(max()); object.reSize(max()); scaleExp.reSize(max()); } /// Returns number of used nonzero entries. int memSize() const { return SVSetBase::memSize(); } /// Returns length of nonzero memory. int memMax() const { return SVSetBase::memMax(); } /// Reallocates memory to be able to store \p newmax nonzeros. void memRemax(int newmax) { SVSetBase::memRemax(newmax); } /// Garbage collection in nonzero memory. void memPack() { SVSetBase::memPack(); } ///@} // ------------------------------------------------------------------------------------------------------------------ /**@name Consistency check */ /// Checks consistency. bool isConsistent() const { #ifdef ENABLE_CONSISTENCY_CHECKS const int ldim = left.dim(); if(ldim != right.dim()) return MSGinconsistent("LPRowSetBase"); if(ldim != object.dim()) return MSGinconsistent("LPRowSetBase"); if(ldim != num()) return MSGinconsistent("LPRowSetBase"); return SVSetBase::isConsistent(); #else return true; #endif } ///@} // ------------------------------------------------------------------------------------------------------------------ /**@name Construction / Destruction */ ///@{ /// Default constructor. /** The user can specify the initial maximum number of rows \p max and the initial maximum number of nonzero entries * \p memmax. If these parameters are omitted, a default size is used. However, one can add an arbitrary number of * rows to the LPRowSetBase, which may result in automated memory realllocation. */ explicit LPRowSetBase(int pmax = -1, int pmemmax = -1) : SVSetBase(pmax, pmemmax), left(0), right(0), object(0), scaleExp(0) { assert(isConsistent()); } /// Assignment operator. LPRowSetBase& operator=(const LPRowSetBase& rs) { if(this != &rs) { SVSetBase::operator=(rs); left = rs.left; right = rs.right; object = rs.object; scaleExp = rs.scaleExp; assert(isConsistent()); } return *this; } /// Assignment operator. template < class S > LPRowSetBase& operator=(const LPRowSetBase& rs) { if(this != (const LPRowSetBase*)(&rs)) { SVSetBase::operator=(rs); left = rs.left; right = rs.right; object = rs.object; scaleExp = rs.scaleExp; assert(isConsistent()); } return *this; } /// Copy constructor. LPRowSetBase(const LPRowSetBase& rs) : SVSetBase(rs) , left(rs.left) , right(rs.right) , object(rs.object) , scaleExp(rs.scaleExp) { assert(isConsistent()); } /// Copy constructor. template < class S > LPRowSetBase(const LPRowSetBase& rs) : SVSetBase(rs) , left(rs.left) , right(rs.right) , object(rs.object) , scaleExp(rs.scaleExp) { assert(isConsistent()); } /// Destructor. virtual ~LPRowSetBase() {} ///@} }; } // namespace soplex #endif // _LPROWSETBASE_H_