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 OsiCuts_H |
6 | #define OsiCuts_H |
7 | |
8 | #include "CoinPragma.hpp" |
9 | |
10 | #include <cmath> |
11 | #include <cfloat> |
12 | #include "OsiCollections.hpp" |
13 | #include "OsiRowCut.hpp" |
14 | #include "OsiColCut.hpp" |
15 | #include "CoinFloatEqual.hpp" |
16 | |
17 | /** Collections of row cuts and column cuts |
18 | */ |
19 | class OsiCuts { |
20 | friend void OsiCutsUnitTest(); |
21 | |
22 | public: |
23 | /**@name Iterator classes |
24 | */ |
25 | //@{ |
26 | /** Iterator |
27 | |
28 | This is a class for iterating over the collection of cuts. |
29 | */ |
30 | class iterator { |
31 | friend class OsiCuts; |
32 | public: |
33 | iterator(OsiCuts& cuts); |
34 | iterator(const iterator & src); |
35 | iterator & operator=( const iterator& rhs); |
36 | ~iterator (); |
37 | OsiCut* operator*() const { return cutP_; } |
38 | iterator operator++(); |
39 | |
40 | iterator operator++(int) |
41 | { |
42 | iterator temp = *this; |
43 | ++*this; |
44 | return temp; |
45 | } |
46 | |
47 | bool operator==(const iterator& it) const { |
48 | return (colCutIndex_+rowCutIndex_)==(it.colCutIndex_+it.rowCutIndex_); |
49 | } |
50 | |
51 | bool operator!=(const iterator& it) const { |
52 | return !((*this)==it); |
53 | } |
54 | |
55 | bool operator<(const iterator& it) const { |
56 | return (colCutIndex_+rowCutIndex_)<(it.colCutIndex_+it.rowCutIndex_); |
57 | } |
58 | |
59 | private: |
60 | iterator(); |
61 | // *THINK* : how to inline these without sticking the code here (ugly...) |
62 | iterator begin(); |
63 | iterator end(); |
64 | OsiCuts& cuts_; |
65 | int rowCutIndex_; |
66 | int colCutIndex_; |
67 | OsiCut * cutP_; |
68 | }; |
69 | |
70 | /** Const Iterator |
71 | |
72 | This is a class for iterating over the collection of cuts. |
73 | */ |
74 | class const_iterator { |
75 | friend class OsiCuts; |
76 | public: |
77 | typedef std::bidirectional_iterator_tag iterator_category; |
78 | typedef OsiCut* value_type; |
79 | typedef size_t difference_type; |
80 | typedef OsiCut ** pointer; |
81 | typedef OsiCut *& reference; |
82 | |
83 | public: |
84 | const_iterator(const OsiCuts& cuts); |
85 | const_iterator(const const_iterator & src); |
86 | const_iterator & operator=( const const_iterator& rhs); |
87 | ~const_iterator (); |
88 | const OsiCut* operator*() const { return cutP_; } |
89 | |
90 | const_iterator operator++(); |
91 | |
92 | const_iterator operator++(int) |
93 | { |
94 | const_iterator temp = *this; |
95 | ++*this; |
96 | return temp; |
97 | } |
98 | |
99 | //hedtke: Visual Studio 2014 asks for "--" operator, so here is one. |
100 | const_iterator operator--(); |
101 | |
102 | bool operator==(const const_iterator& it) const { |
103 | return (colCutIndex_+rowCutIndex_)==(it.colCutIndex_+it.rowCutIndex_); |
104 | } |
105 | |
106 | bool operator!=(const const_iterator& it) const { |
107 | return !((*this)==it); |
108 | } |
109 | |
110 | bool operator<(const const_iterator& it) const { |
111 | return (colCutIndex_+rowCutIndex_)<(it.colCutIndex_+it.rowCutIndex_); |
112 | } |
113 | private: |
114 | inline const_iterator(); |
115 | // *THINK* : how to inline these without sticking the code here (ugly...) |
116 | const_iterator begin(); |
117 | const_iterator end(); |
118 | const OsiCuts * cutsPtr_; |
119 | int rowCutIndex_; |
120 | int colCutIndex_; |
121 | const OsiCut * cutP_; |
122 | }; |
123 | //@} |
124 | |
125 | //------------------------------------------------------------------- |
126 | // |
127 | // Cuts class definition begins here: |
128 | // |
129 | //------------------------------------------------------------------- |
130 | |
131 | /** \name Inserting a cut into collection */ |
132 | //@{ |
133 | /** \brief Insert a row cut */ |
134 | inline void insert( const OsiRowCut & rc ); |
135 | /** \brief Insert a row cut unless it is a duplicate - cut may get sorted. |
136 | Duplicate is defined as CoinAbsFltEq says same*/ |
137 | void insertIfNotDuplicate( OsiRowCut & rc , CoinAbsFltEq treatAsSame=CoinAbsFltEq(1.0e-12) ); |
138 | /** \brief Insert a row cut unless it is a duplicate - cut may get sorted. |
139 | Duplicate is defined as CoinRelFltEq says same*/ |
140 | void insertIfNotDuplicate( OsiRowCut & rc , CoinRelFltEq treatAsSame ); |
141 | /** \brief Insert a column cut */ |
142 | inline void insert( const OsiColCut & cc ); |
143 | |
144 | /** \brief Insert a row cut. |
145 | |
146 | The OsiCuts object takes control of the cut object. |
147 | On return, \c rcPtr is NULL. |
148 | */ |
149 | inline void insert( OsiRowCut * & rcPtr ); |
150 | /** \brief Insert a column cut. |
151 | |
152 | The OsiCuts object takes control of the cut object. |
153 | On return \c ccPtr is NULL. |
154 | */ |
155 | inline void insert( OsiColCut * & ccPtr ); |
156 | #if 0 |
157 | inline void insert( OsiCut * & cPtr ); |
158 | #endif |
159 | |
160 | /** \brief Insert a set of cuts */ |
161 | inline void insert(const OsiCuts & cs); |
162 | |
163 | //@} |
164 | |
165 | /**@name Number of cuts in collection */ |
166 | //@{ |
167 | /// Number of row cuts in collection |
168 | inline int sizeRowCuts() const; |
169 | /// Number of column cuts in collection |
170 | inline int sizeColCuts() const; |
171 | /// Number of cuts in collection |
172 | inline int sizeCuts() const; |
173 | //@} |
174 | |
175 | /**@name Debug stuff */ |
176 | //@{ |
177 | /// Print cuts in collection |
178 | inline void printCuts() const; |
179 | //@} |
180 | |
181 | /**@name Get a cut from collection */ |
182 | //@{ |
183 | /// Get pointer to i'th row cut |
184 | inline OsiRowCut * rowCutPtr(int i); |
185 | /// Get const pointer to i'th row cut |
186 | inline const OsiRowCut * rowCutPtr(int i) const; |
187 | /// Get pointer to i'th column cut |
188 | inline OsiColCut * colCutPtr(int i); |
189 | /// Get const pointer to i'th column cut |
190 | inline const OsiColCut * colCutPtr(int i) const; |
191 | |
192 | /// Get reference to i'th row cut |
193 | inline OsiRowCut & rowCut(int i); |
194 | /// Get const reference to i'th row cut |
195 | inline const OsiRowCut & rowCut(int i) const; |
196 | /// Get reference to i'th column cut |
197 | inline OsiColCut & colCut(int i); |
198 | /// Get const reference to i'th column cut |
199 | inline const OsiColCut & colCut(int i) const; |
200 | |
201 | /// Get const pointer to the most effective cut |
202 | inline const OsiCut * mostEffectiveCutPtr() const; |
203 | /// Get pointer to the most effective cut |
204 | inline OsiCut * mostEffectiveCutPtr(); |
205 | //@} |
206 | |
207 | /**@name Deleting cut from collection */ |
208 | //@{ |
209 | /// Remove i'th row cut from collection |
210 | inline void eraseRowCut(int i); |
211 | /// Remove i'th column cut from collection |
212 | inline void eraseColCut(int i); |
213 | /// Get pointer to i'th row cut and remove ptr from collection |
214 | inline OsiRowCut * rowCutPtrAndZap(int i); |
215 | /*! \brief Clear all row cuts without deleting them |
216 | |
217 | Handy in case one wants to use CGL without managing cuts in one of |
218 | the OSI containers. Client is ultimately responsible for deleting the |
219 | data structures holding the row cuts. |
220 | */ |
221 | inline void dumpCuts() ; |
222 | /*! \brief Selective delete and clear for row cuts. |
223 | |
224 | Deletes the cuts specified in \p to_erase then clears remaining cuts |
225 | without deleting them. A hybrid of eraseRowCut(int) and dumpCuts(). |
226 | Client is ultimately responsible for deleting the data structures |
227 | for row cuts not specified in \p to_erase. |
228 | */ |
229 | inline void eraseAndDumpCuts(const std::vector<int> &to_erase) ; |
230 | //@} |
231 | |
232 | /**@name Sorting collection */ |
233 | //@{ |
234 | /// Cuts with greatest effectiveness are first. |
235 | inline void sort(); |
236 | //@} |
237 | |
238 | |
239 | /**@name Iterators |
240 | Example of using an iterator to sum effectiveness |
241 | of all cuts in the collection. |
242 | <pre> |
243 | double sumEff=0.0; |
244 | for ( OsiCuts::iterator it=cuts.begin(); it!=cuts.end(); ++it ) |
245 | sumEff+= (*it)->effectiveness(); |
246 | </pre> |
247 | */ |
248 | //@{ |
249 | /// Get iterator to beginning of collection |
250 | inline iterator begin() { iterator it(*this); it.begin(); return it; } |
251 | /// Get const iterator to beginning of collection |
252 | inline const_iterator begin() const { const_iterator it(*this); it.begin(); return it; } |
253 | /// Get iterator to end of collection |
254 | inline iterator end() { iterator it(*this); it.end(); return it; } |
255 | /// Get const iterator to end of collection |
256 | inline const_iterator end() const { const_iterator it(*this); it.end(); return it; } |
257 | //@} |
258 | |
259 | |
260 | /**@name Constructors and destructors */ |
261 | //@{ |
262 | /// Default constructor |
263 | OsiCuts (); |
264 | |
265 | /// Copy constructor |
266 | OsiCuts ( const OsiCuts &); |
267 | |
268 | /// Assignment operator |
269 | OsiCuts & operator=( const OsiCuts& rhs); |
270 | |
271 | /// Destructor |
272 | virtual ~OsiCuts (); |
273 | //@} |
274 | |
275 | private: |
276 | //*@name Function operator for sorting cuts by efectiveness */ |
277 | //@{ |
278 | class OsiCutCompare |
279 | { |
280 | public: |
281 | /// Function for sorting cuts by effectiveness |
282 | inline bool operator()(const OsiCut * c1P,const OsiCut * c2P) |
283 | { return c1P->effectiveness() > c2P->effectiveness(); } |
284 | }; |
285 | //@} |
286 | |
287 | /**@name Private methods */ |
288 | //@{ |
289 | /// Copy internal data |
290 | void gutsOfCopy( const OsiCuts & source ); |
291 | /// Delete internal data |
292 | void gutsOfDestructor(); |
293 | //@} |
294 | |
295 | /**@name Private member data */ |
296 | //@{ |
297 | /// Vector of row cuts pointers |
298 | OsiVectorRowCutPtr rowCutPtrs_; |
299 | /// Vector of column cuts pointers |
300 | OsiVectorColCutPtr colCutPtrs_; |
301 | //@} |
302 | |
303 | }; |
304 | |
305 | |
306 | //------------------------------------------------------------------- |
307 | // insert cuts into collection |
308 | //------------------------------------------------------------------- |
309 | void OsiCuts::insert( const OsiRowCut & rc ) |
310 | { |
311 | OsiRowCut * newCutPtr = rc.clone(); |
312 | //assert(dynamic_cast<OsiRowCut*>(newCutPtr) != NULL ); |
313 | rowCutPtrs_.push_back(static_cast<OsiRowCut*>(newCutPtr)); |
314 | } |
315 | void OsiCuts::insert( const OsiColCut & cc ) |
316 | { |
317 | OsiColCut * newCutPtr = cc.clone(); |
318 | //assert(dynamic_cast<OsiColCut*>(newCutPtr) != NULL ); |
319 | colCutPtrs_.push_back(static_cast<OsiColCut*>(newCutPtr)); |
320 | } |
321 | |
322 | void OsiCuts::insert( OsiRowCut* & rcPtr ) |
323 | { |
324 | rowCutPtrs_.push_back(rcPtr); |
325 | rcPtr = nullptr; |
326 | } |
327 | void OsiCuts::insert( OsiColCut* &ccPtr ) |
328 | { |
329 | colCutPtrs_.push_back(ccPtr); |
330 | ccPtr = nullptr; |
331 | } |
332 | #if 0 |
333 | void OsiCuts::insert( OsiCut* & cPtr ) |
334 | { |
335 | OsiRowCut * rcPtr = dynamic_cast<OsiRowCut*>(cPtr); |
336 | if ( rcPtr != NULL ) { |
337 | insert( rcPtr ); |
338 | cPtr = rcPtr; |
339 | } |
340 | else { |
341 | OsiColCut * ccPtr = dynamic_cast<OsiColCut*>(cPtr); |
342 | assert( ccPtr != NULL ); |
343 | insert( ccPtr ); |
344 | cPtr = ccPtr; |
345 | } |
346 | } |
347 | #endif |
348 | |
349 | // LANNEZ SEBASTIEN added Thu May 25 01:22:51 EDT 2006 |
350 | void OsiCuts::insert(const OsiCuts & cs) |
351 | { |
352 | for (OsiCuts::const_iterator it = cs.begin (); it != cs.end (); ++it) |
353 | { |
354 | const OsiRowCut * rCut = dynamic_cast <const OsiRowCut * >(*it); |
355 | const OsiColCut * cCut = dynamic_cast <const OsiColCut * >(*it); |
356 | assert (rCut || cCut); |
357 | if (rCut) |
358 | insert (*rCut); |
359 | else |
360 | insert (*cCut); |
361 | } |
362 | } |
363 | |
364 | //------------------------------------------------------------------- |
365 | // sort |
366 | //------------------------------------------------------------------- |
367 | void OsiCuts::sort() |
368 | { |
369 | std::sort(colCutPtrs_.begin(),colCutPtrs_.end(),OsiCutCompare()); |
370 | std::sort(rowCutPtrs_.begin(),rowCutPtrs_.end(),OsiCutCompare()); |
371 | } |
372 | |
373 | |
374 | //------------------------------------------------------------------- |
375 | // Get number of in collections |
376 | //------------------------------------------------------------------- |
377 | int OsiCuts::sizeRowCuts() const { |
378 | return static_cast<int>(rowCutPtrs_.size()); } |
379 | int OsiCuts::sizeColCuts() const { |
380 | return static_cast<int>(colCutPtrs_.size()); } |
381 | int OsiCuts::sizeCuts() const { |
382 | return static_cast<int>(sizeRowCuts()+sizeColCuts()); } |
383 | |
384 | //---------------------------------------------------------------- |
385 | // Get i'th cut from the collection |
386 | //---------------------------------------------------------------- |
387 | const OsiRowCut * OsiCuts::rowCutPtr(int i) const { return rowCutPtrs_[i]; } |
388 | const OsiColCut * OsiCuts::colCutPtr(int i) const { return colCutPtrs_[i]; } |
389 | OsiRowCut * OsiCuts::rowCutPtr(int i) { return rowCutPtrs_[i]; } |
390 | OsiColCut * OsiCuts::colCutPtr(int i) { return colCutPtrs_[i]; } |
391 | |
392 | const OsiRowCut & OsiCuts::rowCut(int i) const { return *rowCutPtr(i); } |
393 | const OsiColCut & OsiCuts::colCut(int i) const { return *colCutPtr(i); } |
394 | OsiRowCut & OsiCuts::rowCut(int i) { return *rowCutPtr(i); } |
395 | OsiColCut & OsiCuts::colCut(int i) { return *colCutPtr(i); } |
396 | |
397 | //---------------------------------------------------------------- |
398 | // Get most effective cut from collection |
399 | //---------------------------------------------------------------- |
400 | const OsiCut * OsiCuts::mostEffectiveCutPtr() const |
401 | { |
402 | const_iterator b=begin(); |
403 | const_iterator e=end(); |
404 | return *(std::min_element(b,e,OsiCutCompare())); |
405 | } |
406 | OsiCut * OsiCuts::mostEffectiveCutPtr() |
407 | { |
408 | iterator b=begin(); |
409 | iterator e=end(); |
410 | //return *(std::min_element(b,e,OsiCutCompare())); |
411 | OsiCut * retVal = nullptr; |
412 | double maxEff = COIN_DBL_MIN; |
413 | for ( OsiCuts::iterator it=b; it!=e; ++it ) { |
414 | if (maxEff < (*it)->effectiveness() ) { |
415 | maxEff = (*it)->effectiveness(); |
416 | retVal = *it; |
417 | } |
418 | } |
419 | return retVal; |
420 | } |
421 | |
422 | //---------------------------------------------------------------- |
423 | // Print all cuts |
424 | //---------------------------------------------------------------- |
425 | void |
426 | OsiCuts::printCuts() const |
427 | { |
428 | // do all column cuts first |
429 | int i; |
430 | int numberColCuts=sizeColCuts(); |
431 | for (i=0;i<numberColCuts;i++) { |
432 | const OsiColCut * cut = colCutPtr(i); |
433 | cut->print(); |
434 | } |
435 | int numberRowCuts=sizeRowCuts(); |
436 | for (i=0;i<numberRowCuts;i++) { |
437 | const OsiRowCut * cut = rowCutPtr(i); |
438 | cut->print(); |
439 | } |
440 | } |
441 | |
442 | //---------------------------------------------------------------- |
443 | // Erase i'th cut from the collection |
444 | //---------------------------------------------------------------- |
445 | void OsiCuts::eraseRowCut(int i) |
446 | { |
447 | delete rowCutPtrs_[i]; |
448 | rowCutPtrs_.erase( rowCutPtrs_.begin()+i ); |
449 | } |
450 | void OsiCuts::eraseColCut(int i) |
451 | { |
452 | delete colCutPtrs_[i]; |
453 | colCutPtrs_.erase( colCutPtrs_.begin()+i ); |
454 | } |
455 | /// Get pointer to i'th row cut and remove ptr from collection |
456 | OsiRowCut * |
457 | OsiCuts::rowCutPtrAndZap(int i) |
458 | { |
459 | OsiRowCut * cut = rowCutPtrs_[i]; |
460 | rowCutPtrs_[i]=nullptr; |
461 | rowCutPtrs_.erase( rowCutPtrs_.begin()+i ); |
462 | return cut; |
463 | } |
464 | void OsiCuts::dumpCuts() |
465 | { |
466 | rowCutPtrs_.clear() ; |
467 | } |
468 | void OsiCuts::eraseAndDumpCuts(const std::vector<int> &to_erase) |
469 | { |
470 | for (unsigned i=0; i<to_erase.size(); i++) { |
471 | delete rowCutPtrs_[to_erase[i]]; |
472 | } |
473 | rowCutPtrs_.clear(); |
474 | } |
475 | |
476 | |
477 | #endif |
478 | |