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 #if defined(_MSC_VER)
6 // Turn off compiler warning about long names
7 #pragma warning(disable : 4786)
8 #endif
9 
10 #include <algorithm>
11 #include <cassert>
12 
13 #include "OsiCuts.hpp"
14 
15 //-------------------------------------------------------------------
16 // Default Constructor
17 //-------------------------------------------------------------------
OsiCuts()18 OsiCuts::OsiCuts()
19   : rowCutPtrs_()
20   , colCutPtrs_()
21 {
22   // nothing to do here
23 }
24 
25 //-------------------------------------------------------------------
26 // Copy constructor
27 //-------------------------------------------------------------------
OsiCuts(const OsiCuts & source)28 OsiCuts::OsiCuts(const OsiCuts &source)
29   : rowCutPtrs_()
30   , colCutPtrs_()
31 {
32   gutsOfCopy(source);
33 }
34 
35 //-------------------------------------------------------------------
36 // Destructor
37 //-------------------------------------------------------------------
~OsiCuts()38 OsiCuts::~OsiCuts()
39 {
40   gutsOfDestructor();
41 }
42 
43 //----------------------------------------------------------------
44 // Assignment operator
45 //-------------------------------------------------------------------
46 OsiCuts &
operator =(const OsiCuts & rhs)47 OsiCuts::operator=(const OsiCuts &rhs)
48 {
49   if (this != &rhs) {
50     gutsOfDestructor();
51     gutsOfCopy(rhs);
52   }
53   return *this;
54 }
55 
56 //-------------------------------------------------------------------
gutsOfCopy(const OsiCuts & source)57 void OsiCuts::gutsOfCopy(const OsiCuts &source)
58 {
59   assert(sizeRowCuts() == 0);
60   assert(sizeColCuts() == 0);
61   assert(sizeCuts() == 0);
62   int i;
63   int ne = source.sizeRowCuts();
64   for (i = 0; i < ne; i++)
65     insert(source.rowCut(i));
66   ne = source.sizeColCuts();
67   for (i = 0; i < ne; i++)
68     insert(source.colCut(i));
69 }
70 
71 //-------------------------------------------------------------------
gutsOfDestructor()72 void OsiCuts::gutsOfDestructor()
73 {
74   int i;
75 
76   int ne = static_cast< int >(rowCutPtrs_.size());
77   for (i = 0; i < ne; i++) {
78     if (rowCutPtrs_[i]->globallyValidAsInteger() != 2)
79       delete rowCutPtrs_[i];
80   }
81   rowCutPtrs_.clear();
82 
83   ne = static_cast< int >(colCutPtrs_.size());
84   for (i = 0; i < ne; i++) {
85     if (colCutPtrs_[i]->globallyValidAsInteger() != 2)
86       delete colCutPtrs_[i];
87   }
88   colCutPtrs_.clear();
89 
90   assert(sizeRowCuts() == 0);
91   assert(sizeColCuts() == 0);
92   assert(sizeCuts() == 0);
93 }
94 
95 //------------------------------------------------------------
96 //
97 // Embedded iterator class implementation
98 //
99 //------------------------------------------------------------
iterator(OsiCuts & cuts)100 OsiCuts::iterator::iterator(OsiCuts &cuts)
101   : cuts_(cuts)
102   , rowCutIndex_(-1)
103   , colCutIndex_(-1)
104   , cutP_(NULL)
105 {
106   this->operator++();
107 }
108 
iterator(const OsiCuts::iterator & src)109 OsiCuts::iterator::iterator(const OsiCuts::iterator &src)
110   : cuts_(src.cuts_)
111   , rowCutIndex_(src.rowCutIndex_)
112   , colCutIndex_(src.colCutIndex_)
113   , cutP_(src.cutP_)
114 {
115   // nothing to do here
116 }
117 
operator =(const OsiCuts::iterator & rhs)118 OsiCuts::iterator &OsiCuts::iterator::operator=(const OsiCuts::iterator &rhs)
119 {
120   if (this != &rhs) {
121     cuts_ = rhs.cuts_;
122     rowCutIndex_ = rhs.rowCutIndex_;
123     colCutIndex_ = rhs.colCutIndex_;
124     cutP_ = rhs.cutP_;
125   }
126   return *this;
127 }
128 
~iterator()129 OsiCuts::iterator::~iterator()
130 {
131   //nothing to do
132 }
133 
begin()134 OsiCuts::iterator OsiCuts::iterator::begin()
135 {
136   rowCutIndex_ = -1;
137   colCutIndex_ = -1;
138   this->operator++();
139   return *this;
140 }
141 
end()142 OsiCuts::iterator OsiCuts::iterator::end()
143 {
144   rowCutIndex_ = cuts_.sizeRowCuts();
145   colCutIndex_ = cuts_.sizeColCuts() - 1;
146   cutP_ = NULL;
147   return *this;
148 }
149 
operator ++()150 OsiCuts::iterator OsiCuts::iterator::operator++()
151 {
152   cutP_ = NULL;
153 
154   // Are there any more row cuts to consider?
155   if ((rowCutIndex_ + 1) >= cuts_.sizeRowCuts()) {
156     // Only column cuts left.
157     colCutIndex_++;
158     // Only update cutP if there is a column cut.
159     // This is necessary for the iterator to work for
160     // OsiCuts that don't have any cuts.
161     if (cuts_.sizeColCuts() > 0 && colCutIndex_ < cuts_.sizeColCuts())
162       cutP_ = cuts_.colCutPtr(colCutIndex_);
163   }
164 
165   // Are there any more col cuts to consider?
166   else if ((colCutIndex_ + 1) >= cuts_.sizeColCuts()) {
167     // Only row cuts left
168     rowCutIndex_++;
169     if (rowCutIndex_ < cuts_.sizeRowCuts())
170       cutP_ = cuts_.rowCutPtr(rowCutIndex_);
171   }
172 
173   // There are still Row & column cuts left to consider
174   else {
175     double nextColCutE = cuts_.colCut(colCutIndex_ + 1).effectiveness();
176     double nextRowCutE = cuts_.rowCut(rowCutIndex_ + 1).effectiveness();
177     if (nextColCutE > nextRowCutE) {
178       colCutIndex_++;
179       cutP_ = cuts_.colCutPtr(colCutIndex_);
180     } else {
181       rowCutIndex_++;
182       cutP_ = cuts_.rowCutPtr(rowCutIndex_);
183     }
184   }
185   return *this;
186 }
187 
188 //------------------------------------------------------------
189 //
190 // Embedded const_iterator class implementation
191 //
192 //------------------------------------------------------------
const_iterator(const OsiCuts & cuts)193 OsiCuts::const_iterator::const_iterator(const OsiCuts &cuts)
194   : cutsPtr_(&cuts)
195   , rowCutIndex_(-1)
196   , colCutIndex_(-1)
197   , cutP_(NULL)
198 {
199   this->operator++();
200 }
201 
const_iterator(const OsiCuts::const_iterator & src)202 OsiCuts::const_iterator::const_iterator(const OsiCuts::const_iterator &src)
203   : cutsPtr_(src.cutsPtr_)
204   , rowCutIndex_(src.rowCutIndex_)
205   , colCutIndex_(src.colCutIndex_)
206   , cutP_(src.cutP_)
207 {
208   // nothing to do here
209 }
210 
211 OsiCuts::const_iterator &
operator =(const OsiCuts::const_iterator & rhs)212 OsiCuts::const_iterator::operator=(const OsiCuts::const_iterator &rhs)
213 {
214   if (this != &rhs) {
215     cutsPtr_ = rhs.cutsPtr_;
216     rowCutIndex_ = rhs.rowCutIndex_;
217     colCutIndex_ = rhs.colCutIndex_;
218     cutP_ = rhs.cutP_;
219   }
220   return *this;
221 }
222 
~const_iterator()223 OsiCuts::const_iterator::~const_iterator()
224 {
225   //nothing to do
226 }
227 
begin()228 OsiCuts::const_iterator OsiCuts::const_iterator::begin()
229 {
230   rowCutIndex_ = -1;
231   colCutIndex_ = -1;
232   this->operator++();
233   return *this;
234 }
235 
end()236 OsiCuts::const_iterator OsiCuts::const_iterator::end()
237 {
238   rowCutIndex_ = cutsPtr_->sizeRowCuts();
239   colCutIndex_ = cutsPtr_->sizeColCuts() - 1;
240   cutP_ = NULL;
241   return *this;
242 }
243 
operator ++()244 OsiCuts::const_iterator OsiCuts::const_iterator::operator++()
245 {
246   cutP_ = NULL;
247 
248   // Are there any more row cuts to consider?
249   if ((rowCutIndex_ + 1) >= cutsPtr_->sizeRowCuts()) {
250     // Only column cuts left.
251     colCutIndex_++;
252     // Only update cutP if there is a column cut.
253     // This is necessary for the iterator to work for
254     // OsiCuts that don't have any cuts.
255     if (cutsPtr_->sizeRowCuts() > 0 && colCutIndex_ < cutsPtr_->sizeColCuts())
256       cutP_ = cutsPtr_->colCutPtr(colCutIndex_);
257   }
258 
259   // Are there any more col cuts to consider?
260   else if ((colCutIndex_ + 1) >= cutsPtr_->sizeColCuts()) {
261     // Only row cuts left
262     rowCutIndex_++;
263     if (rowCutIndex_ < cutsPtr_->sizeRowCuts())
264       cutP_ = cutsPtr_->rowCutPtr(rowCutIndex_);
265   }
266 
267   // There are still Row & column cuts left to consider
268   else {
269     double nextColCutE = cutsPtr_->colCut(colCutIndex_ + 1).effectiveness();
270     double nextRowCutE = cutsPtr_->rowCut(rowCutIndex_ + 1).effectiveness();
271     if (nextColCutE > nextRowCutE) {
272       colCutIndex_++;
273       cutP_ = cutsPtr_->colCutPtr(colCutIndex_);
274     } else {
275       rowCutIndex_++;
276       cutP_ = cutsPtr_->rowCutPtr(rowCutIndex_);
277     }
278   }
279   return *this;
280 }
281 
282 /* Insert a row cut unless it is a duplicate (CoinAbsFltEq)*/
insertIfNotDuplicate(OsiRowCut & rc,CoinAbsFltEq treatAsSame)283 void OsiCuts::insertIfNotDuplicate(OsiRowCut &rc, CoinAbsFltEq treatAsSame)
284 {
285   double newLb = rc.lb();
286   double newUb = rc.ub();
287   CoinPackedVector vector = rc.row();
288   int numberElements = vector.getNumElements();
289   int *newIndices = vector.getIndices();
290   double *newElements = vector.getElements();
291   CoinSort_2(newIndices, newIndices + numberElements, newElements);
292   bool notDuplicate = true;
293   int numberRowCuts = sizeRowCuts();
294   for (int i = 0; i < numberRowCuts; i++) {
295     const OsiRowCut *cutPtr = rowCutPtr(i);
296     if (cutPtr->row().getNumElements() != numberElements)
297       continue;
298     if (!treatAsSame(cutPtr->lb(), newLb))
299       continue;
300     if (!treatAsSame(cutPtr->ub(), newUb))
301       continue;
302     const CoinPackedVector *thisVector = &(cutPtr->row());
303     const int *indices = thisVector->getIndices();
304     const double *elements = thisVector->getElements();
305     int j;
306     for (j = 0; j < numberElements; j++) {
307       if (indices[j] != newIndices[j])
308         break;
309       if (!treatAsSame(elements[j], newElements[j]))
310         break;
311     }
312     if (j == numberElements) {
313       notDuplicate = false;
314       break;
315     }
316   }
317   if (notDuplicate) {
318     OsiRowCut *newCutPtr = new OsiRowCut();
319     newCutPtr->setLb(newLb);
320     newCutPtr->setUb(newUb);
321     newCutPtr->setRow(vector);
322     newCutPtr->setGloballyValid(rc.globallyValid());
323     newCutPtr->setEffectiveness(rc.effectiveness());
324     rowCutPtrs_.push_back(newCutPtr);
325   }
326 }
327 
328 /* Insert a row cut unless it is a duplicate (CoinRelFltEq)*/
insertIfNotDuplicate(OsiRowCut & rc,CoinRelFltEq treatAsSame)329 void OsiCuts::insertIfNotDuplicate(OsiRowCut &rc, CoinRelFltEq treatAsSame)
330 {
331   double newLb = rc.lb();
332   double newUb = rc.ub();
333   CoinPackedVector vector = rc.row();
334   int numberElements = vector.getNumElements();
335   int *newIndices = vector.getIndices();
336   double *newElements = vector.getElements();
337   CoinSort_2(newIndices, newIndices + numberElements, newElements);
338   bool notDuplicate = true;
339   int numberRowCuts = sizeRowCuts();
340   for (int i = 0; i < numberRowCuts; i++) {
341     const OsiRowCut *cutPtr = rowCutPtr(i);
342     if (cutPtr->row().getNumElements() != numberElements)
343       continue;
344     if (!treatAsSame(cutPtr->lb(), newLb))
345       continue;
346     if (!treatAsSame(cutPtr->ub(), newUb))
347       continue;
348     const CoinPackedVector *thisVector = &(cutPtr->row());
349     const int *indices = thisVector->getIndices();
350     const double *elements = thisVector->getElements();
351     int j;
352     for (j = 0; j < numberElements; j++) {
353       if (indices[j] != newIndices[j])
354         break;
355       if (!treatAsSame(elements[j], newElements[j]))
356         break;
357     }
358     if (j == numberElements) {
359       notDuplicate = false;
360       break;
361     }
362   }
363   if (notDuplicate) {
364     OsiRowCut *newCutPtr = new OsiRowCut();
365     newCutPtr->setLb(newLb);
366     newCutPtr->setUb(newUb);
367     newCutPtr->setRow(vector);
368     newCutPtr->setGloballyValid(rc.globallyValid());
369     newCutPtr->setEffectiveness(rc.effectiveness());
370     rowCutPtrs_.push_back(newCutPtr);
371   }
372 }
373 
374 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
375 */
376