1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others.  All Rights Reserved.
3 // This code is licensed under the terms of the Eclipse Public License (EPL).
4 
5 #ifndef OsiColCut_H
6 #define OsiColCut_H
7 
8 #include <string>
9 
10 #include "CoinPackedVector.hpp"
11 
12 #include "OsiCollections.hpp"
13 #include "OsiCut.hpp"
14 
15 /** Column Cut Class
16 
17 Column Cut Class has:
18   <ul>
19   <li>a sparse vector of column lower bounds
20   <li>a sparse vector of column upper bounds
21   </ul>
22 */
23 class OsiColCut : public OsiCut {
24    friend void OsiColCutUnitTest(const OsiSolverInterface * baseSiP,
25 				 const std::string & mpsDir);
26 
27 public:
28 
29   //----------------------------------------------------------------
30 
31   /**@name Setting column bounds */
32   //@{
33   /// Set column lower bounds
34   inline void setLbs(
35     int nElements,
36     const int * colIndices,
37     const double * lbElements );
38 
39   /// Set column lower bounds from a packed vector
40   inline void setLbs( const CoinPackedVector & lbs );
41 
42   /// Set column upper bounds
43   inline void setUbs(
44     int nElements,
45     const int * colIndices,
46     const double * ubElements );
47 
48   /// Set column upper bounds from a packed vector
49   inline void setUbs( const CoinPackedVector & ubs );
50   //@}
51 
52   //----------------------------------------------------------------
53 
54   /**@name Getting column bounds */
55   //@{
56   /// Get column lower bounds
57   inline const CoinPackedVector & lbs() const;
58   /// Get column upper bounds
59   inline const CoinPackedVector & ubs() const;
60   //@}
61 
62   /**@name Comparison operators  */
63   //@{
64 #if __GNUC__ != 2
65   using OsiCut::operator== ;
66 #endif
67   /** equal - true if lower bounds, upper bounds,
68   and OsiCut are equal.
69   */
70   inline virtual bool operator==(const OsiColCut& rhs) const;
71 
72 #if __GNUC__ != 2
73   using OsiCut::operator!= ;
74 #endif
75   /// not equal
76   inline virtual bool operator!=(const OsiColCut& rhs) const;
77   //@}
78 
79 
80   //----------------------------------------------------------------
81 
82   /**@name Sanity checks on cut */
83   //@{
84   /** Returns true if the cut is consistent with respect to itself.
85   This checks to ensure that:
86   <ul>
87   <li>The bound vectors do not have duplicate indices,
88   <li>The bound vectors indices are >=0
89   </ul>
90   */
91   inline virtual bool consistent() const override;
92 
93   /** Returns true if cut is consistent with respect to the solver
94   interface's model. This checks to ensure that
95   the lower & upperbound packed vectors:
96   <ul>
97   <li>do not have an index >= the number of column is the model.
98   </ul>
99   */
100   inline virtual bool consistent(const OsiSolverInterface& im) const override;
101 
102   /** Returns true if the cut is infeasible with respect to its bounds and the
103   column bounds in the solver interface's models.
104   This checks whether:
105   <ul>
106   <li>the maximum of the new and existing lower bounds is strictly
107   greater than the minimum of the new and existing upper bounds.
108 </ul>
109   */
110   inline virtual bool infeasible(const OsiSolverInterface &im) const override;
111   /** Returns infeasibility of the cut with respect to solution
112       passed in i.e. is positive if cuts off that solution.
113       solution is getNumCols() long..
114   */
115   virtual double violated(const double * solution) const override;
116   //@}
117 
118   //----------------------------------------------------------------
119 
120   /**@name Constructors and destructors */
121   //@{
122   /// Assignment operator
123   OsiColCut & operator=( const OsiColCut& rhs);
124 
125   /// Copy constructor
126   OsiColCut ( const OsiColCut &);
127 
128   /// Default Constructor
129   OsiColCut ();
130 
131   /// Clone
132   virtual OsiColCut * clone() const;
133 
134   /// Destructor
135   virtual ~OsiColCut ();
136   //@}
137 
138   /**@name Debug stuff */
139   //@{
140     /// Print cuts in collection
141   virtual void print() const override;
142   //@}
143 
144 private:
145 
146   /**@name Private member data */
147   //@{
148   /// Lower bounds
149   CoinPackedVector lbs_;
150   /// Upper bounds
151   CoinPackedVector ubs_;
152   //@}
153 
154 };
155 
156 
157 
158 //-------------------------------------------------------------------
159 // Set lower & upper bound vectors
160 //-------------------------------------------------------------------
setLbs(int size,const int * colIndices,const double * lbElements)161 void OsiColCut::setLbs(
162                        int size,
163                        const int * colIndices,
164                        const double * lbElements )
165 {
166   lbs_.setVector(size,colIndices,lbElements);
167 }
168 //
setUbs(int size,const int * colIndices,const double * ubElements)169 void OsiColCut::setUbs(
170                        int size,
171                        const int * colIndices,
172                        const double * ubElements )
173 {
174   ubs_.setVector(size,colIndices,ubElements);
175 }
176 //
setLbs(const CoinPackedVector & lbs)177 void OsiColCut::setLbs( const CoinPackedVector & lbs )
178 {
179   lbs_ = lbs;
180 }
181 //
setUbs(const CoinPackedVector & ubs)182 void OsiColCut::setUbs( const CoinPackedVector & ubs )
183 {
184   ubs_ = ubs;
185 }
186 
187 //-------------------------------------------------------------------
188 // Get Column Lower Bounds and Column Upper Bounds
189 //-------------------------------------------------------------------
lbs() const190 const CoinPackedVector & OsiColCut::lbs() const
191 {
192   return lbs_;
193 }
194 //
ubs() const195 const CoinPackedVector & OsiColCut::ubs() const
196 {
197   return ubs_;
198 }
199 
200 //----------------------------------------------------------------
201 // == operator
202 //-------------------------------------------------------------------
203 bool
operator ==(const OsiColCut & rhs) const204 OsiColCut::operator==(
205                       const OsiColCut& rhs) const
206 {
207   if ( this->OsiCut::operator!=(rhs) )
208     return false;
209   if ( lbs() != rhs.lbs() )
210     return false;
211   if ( ubs() != rhs.ubs() )
212     return false;
213   return true;
214 }
215 //
216 bool
operator !=(const OsiColCut & rhs) const217 OsiColCut::operator!=(
218                       const OsiColCut& rhs) const
219 {
220   return !( (*this)==rhs );
221 }
222 
223 //----------------------------------------------------------------
224 // consistent & infeasible
225 //-------------------------------------------------------------------
consistent() const226 bool OsiColCut::consistent() const
227 {
228   const CoinPackedVector & lb = lbs();
229   const CoinPackedVector & ub = ubs();
230   // Test for consistent cut.
231   // Are packed vectors consistent?
232   lb.duplicateIndex("consistent", "OsiColCut");
233   ub.duplicateIndex("consistent", "OsiColCut");
234   if ( lb.getMinIndex() < 0 ) return false;
235   if ( ub.getMinIndex() < 0 ) return false;
236   return true;
237 }
238 //
consistent(const OsiSolverInterface & im) const239 bool OsiColCut::consistent(const OsiSolverInterface& im) const
240 {
241   const CoinPackedVector & lb = lbs();
242   const CoinPackedVector & ub = ubs();
243 
244   // Test for consistent cut.
245   if ( lb.getMaxIndex() >= im.getNumCols() ) return false;
246   if ( ub.getMaxIndex() >= im.getNumCols() ) return false;
247 
248   return true;
249 }
250 
251 #if 0
252 bool OsiColCut::feasible(const OsiSolverInterface &im) const
253 {
254   const double * oldColLb = im.getColLower();
255   const double * oldColUb = im.getColUpper();
256   const CoinPackedVector & cutLbs = lbs();
257   const CoinPackedVector & cutUbs = ubs();
258   int i;
259 
260   for ( i=0; i<cutLbs.size(); i++ ) {
261     int colIndx = cutLbs.indices()[i];
262     double newLb;
263     if ( cutLbs.elements()[i] > oldColLb[colIndx] )
264       newLb = cutLbs.elements()[i];
265     else
266       newLb = oldColLb[colIndx];
267 
268     double newUb = oldColUb[colIndx];
269     if ( cutUbs.indexExists(colIndx) )
270       if ( cutUbs[colIndx] < newUb ) newUb = cutUbs[colIndx];
271       if ( newLb > newUb )
272         return false;
273   }
274 
275   for ( i=0; i<cutUbs.size(); i++ ) {
276     int colIndx = cutUbs.indices()[i];
277     double newUb = cutUbs.elements()[i] < oldColUb[colIndx] ? cutUbs.elements()[i] : oldColUb[colIndx];
278     double newLb = oldColLb[colIndx];
279     if ( cutLbs.indexExists(colIndx) )
280       if ( cutLbs[colIndx] > newLb ) newLb = cutLbs[colIndx];
281       if ( newUb < newLb )
282         return false;
283   }
284 
285   return true;
286 }
287 #endif
288 
289 
infeasible(const OsiSolverInterface & im) const290 bool OsiColCut::infeasible(const OsiSolverInterface &im) const
291 {
292   const double * oldColLb = im.getColLower();
293   const double * oldColUb = im.getColUpper();
294   const CoinPackedVector & cutLbs = lbs();
295   const CoinPackedVector & cutUbs = ubs();
296   int i;
297 
298   for ( i=0; i<cutLbs.getNumElements(); i++ ) {
299     int colIndx = cutLbs.getIndices()[i];
300     double newLb= cutLbs.getElements()[i] > oldColLb[colIndx] ?
301        cutLbs.getElements()[i] : oldColLb[colIndx];
302 
303     double newUb = oldColUb[colIndx];
304     if ( cutUbs.isExistingIndex(colIndx) )
305       if ( cutUbs[colIndx] < newUb ) newUb = cutUbs[colIndx];
306     if ( newLb > newUb )
307       return true;
308   }
309 
310   for ( i=0; i<cutUbs.getNumElements(); i++ ) {
311     int colIndx = cutUbs.getIndices()[i];
312     double newUb = cutUbs.getElements()[i] < oldColUb[colIndx] ?
313        cutUbs.getElements()[i] : oldColUb[colIndx];
314     double newLb = oldColLb[colIndx];
315     if ( cutLbs.isExistingIndex(colIndx) )
316       if ( cutLbs[colIndx] > newLb ) newLb = cutLbs[colIndx];
317     if ( newUb < newLb )
318       return true;
319   }
320 
321   return false;
322 }
323 
324 #endif
325