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