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 | //------------------------------------------------------------------- |
161 | void OsiColCut::setLbs( |
162 | int size, |
163 | const int * colIndices, |
164 | const double * lbElements ) |
165 | { |
166 | lbs_.setVector(size,colIndices,lbElements); |
167 | } |
168 | // |
169 | void OsiColCut::setUbs( |
170 | int size, |
171 | const int * colIndices, |
172 | const double * ubElements ) |
173 | { |
174 | ubs_.setVector(size,colIndices,ubElements); |
175 | } |
176 | // |
177 | void OsiColCut::setLbs( const CoinPackedVector & lbs ) |
178 | { |
179 | lbs_ = lbs; |
180 | } |
181 | // |
182 | void OsiColCut::setUbs( const CoinPackedVector & ubs ) |
183 | { |
184 | ubs_ = ubs; |
185 | } |
186 | |
187 | //------------------------------------------------------------------- |
188 | // Get Column Lower Bounds and Column Upper Bounds |
189 | //------------------------------------------------------------------- |
190 | const CoinPackedVector & OsiColCut::lbs() const |
191 | { |
192 | return lbs_; |
193 | } |
194 | // |
195 | const CoinPackedVector & OsiColCut::ubs() const |
196 | { |
197 | return ubs_; |
198 | } |
199 | |
200 | //---------------------------------------------------------------- |
201 | // == operator |
202 | //------------------------------------------------------------------- |
203 | bool |
204 | 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 |
217 | OsiColCut::operator!=( |
218 | const OsiColCut& rhs) const |
219 | { |
220 | return !( (*this)==rhs ); |
221 | } |
222 | |
223 | //---------------------------------------------------------------- |
224 | // consistent & infeasible |
225 | //------------------------------------------------------------------- |
226 | 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 | // |
239 | 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 | |
290 | 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 | |