limp-cbc-0.3.2.0: cbits/coin/OsiCuts.cpp
// Copyright (C) 2000, International Business Machines
// Corporation and others. All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).
#if defined(_MSC_VER)
// Turn off compiler warning about long names
# pragma warning(disable:4786)
#endif
#include <algorithm>
#include <cassert>
#include "OsiCuts.hpp"
//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
OsiCuts::OsiCuts ()
:
rowCutPtrs_(),
colCutPtrs_()
{
// nothing to do here
}
//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
OsiCuts::OsiCuts (const OsiCuts & source)
:
rowCutPtrs_(),
colCutPtrs_()
{
gutsOfCopy( source );
}
//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
OsiCuts::~OsiCuts ()
{
gutsOfDestructor();
}
//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
OsiCuts &
OsiCuts::operator=(const OsiCuts& rhs)
{
if (this != &rhs) {
gutsOfDestructor();
gutsOfCopy( rhs );
}
return *this;
}
//-------------------------------------------------------------------
void OsiCuts::gutsOfCopy(const OsiCuts& source)
{
assert( sizeRowCuts()==0 );
assert( sizeColCuts()==0 );
assert( sizeCuts()==0 );
int i;
int ne = source.sizeRowCuts();
for (i=0; i<ne; i++) insert( source.rowCut(i) );
ne = source.sizeColCuts();
for (i=0; i<ne; i++) insert( source.colCut(i) );
}
//-------------------------------------------------------------------
void OsiCuts::gutsOfDestructor()
{
int i;
int ne = static_cast<int>(rowCutPtrs_.size());
for (i=0; i<ne; i++) {
if (rowCutPtrs_[i]->globallyValidAsInteger()!=2)
delete rowCutPtrs_[i];
}
rowCutPtrs_.clear();
ne = static_cast<int>(colCutPtrs_.size());
for (i=0; i<ne; i++) {
if (colCutPtrs_[i]->globallyValidAsInteger()!=2)
delete colCutPtrs_[i];
}
colCutPtrs_.clear();
assert( sizeRowCuts()==0 );
assert( sizeColCuts()==0 );
assert( sizeCuts() ==0 );
}
//------------------------------------------------------------
//
// Embedded iterator class implementation
//
//------------------------------------------------------------
OsiCuts::iterator::iterator(OsiCuts& cuts)
:
cuts_(cuts),
rowCutIndex_(-1),
colCutIndex_(-1),
cutP_(NULL)
{
this->operator++();
}
OsiCuts::iterator::iterator(const OsiCuts::iterator &src)
:
cuts_(src.cuts_),
rowCutIndex_(src.rowCutIndex_),
colCutIndex_(src.colCutIndex_),
cutP_(src.cutP_)
{
// nothing to do here
}
OsiCuts::iterator & OsiCuts::iterator::operator=(const OsiCuts::iterator &rhs)
{
if (this != &rhs) {
cuts_=rhs.cuts_;
rowCutIndex_=rhs.rowCutIndex_;
colCutIndex_=rhs.colCutIndex_;
cutP_=rhs.cutP_;
}
return *this;
}
OsiCuts::iterator::~iterator()
{
//nothing to do
}
OsiCuts::iterator OsiCuts::iterator::begin()
{
rowCutIndex_=-1;
colCutIndex_=-1;
this->operator++();
return *this;
}
OsiCuts::iterator OsiCuts::iterator::end()
{
rowCutIndex_=cuts_.sizeRowCuts();
colCutIndex_=cuts_.sizeColCuts()-1;
cutP_=NULL;
return *this;
}
OsiCuts::iterator OsiCuts::iterator::operator++() {
cutP_ = NULL;
// Are there any more row cuts to consider?
if ( (rowCutIndex_+1)>=cuts_.sizeRowCuts() ) {
// Only column cuts left.
colCutIndex_++;
// Only update cutP if there is a column cut.
// This is necessary for the iterator to work for
// OsiCuts that don't have any cuts.
if ( cuts_.sizeColCuts() > 0 && colCutIndex_<cuts_.sizeColCuts() )
cutP_= cuts_.colCutPtr(colCutIndex_);
}
// Are there any more col cuts to consider?
else if ( (colCutIndex_+1)>=cuts_.sizeColCuts() ) {
// Only row cuts left
rowCutIndex_++;
if ( rowCutIndex_<cuts_.sizeRowCuts() )
cutP_= cuts_.rowCutPtr(rowCutIndex_);
}
// There are still Row & column cuts left to consider
else {
double nextColCutE=cuts_.colCut(colCutIndex_+1).effectiveness();
double nextRowCutE=cuts_.rowCut(rowCutIndex_+1).effectiveness();
if ( nextColCutE>nextRowCutE ) {
colCutIndex_++;
cutP_=cuts_.colCutPtr(colCutIndex_);
}
else {
rowCutIndex_++;
cutP_=cuts_.rowCutPtr(rowCutIndex_);
}
}
return *this;
}
//------------------------------------------------------------
//
// Embedded const_iterator class implementation
//
//------------------------------------------------------------
OsiCuts::const_iterator::const_iterator(const OsiCuts& cuts)
:
cutsPtr_(&cuts),
rowCutIndex_(-1),
colCutIndex_(-1),
cutP_(NULL)
{
this->operator++();
}
OsiCuts::const_iterator::const_iterator(const OsiCuts::const_iterator &src)
:
cutsPtr_(src.cutsPtr_),
rowCutIndex_(src.rowCutIndex_),
colCutIndex_(src.colCutIndex_),
cutP_(src.cutP_)
{
// nothing to do here
}
OsiCuts::const_iterator &
OsiCuts::const_iterator::operator=(const OsiCuts::const_iterator &rhs)
{
if (this != &rhs) {
cutsPtr_=rhs.cutsPtr_;
rowCutIndex_=rhs.rowCutIndex_;
colCutIndex_=rhs.colCutIndex_;
cutP_=rhs.cutP_;
}
return *this;
}
OsiCuts::const_iterator::~const_iterator()
{
//nothing to do
}
OsiCuts::const_iterator OsiCuts::const_iterator::begin()
{
rowCutIndex_=-1;
colCutIndex_=-1;
this->operator++();
return *this;
}
OsiCuts::const_iterator OsiCuts::const_iterator::end()
{
rowCutIndex_=cutsPtr_->sizeRowCuts();
colCutIndex_=cutsPtr_->sizeColCuts()-1;
cutP_=NULL;
return *this;
}
OsiCuts::const_iterator OsiCuts::const_iterator::operator++() {
cutP_ = NULL;
// Are there any more row cuts to consider?
if ( (rowCutIndex_+1)>=cutsPtr_->sizeRowCuts() ) {
// Only column cuts left.
colCutIndex_++;
// Only update cutP if there is a column cut.
// This is necessary for the iterator to work for
// OsiCuts that don't have any cuts.
if ( cutsPtr_->sizeRowCuts() > 0 && colCutIndex_<cutsPtr_->sizeColCuts() )
cutP_= cutsPtr_->colCutPtr(colCutIndex_);
}
// Are there any more col cuts to consider?
else if ( (colCutIndex_+1)>=cutsPtr_->sizeColCuts() ) {
// Only row cuts left
rowCutIndex_++;
if ( rowCutIndex_<cutsPtr_->sizeRowCuts() )
cutP_= cutsPtr_->rowCutPtr(rowCutIndex_);
}
// There are still Row & column cuts left to consider
else {
double nextColCutE=cutsPtr_->colCut(colCutIndex_+1).effectiveness();
double nextRowCutE=cutsPtr_->rowCut(rowCutIndex_+1).effectiveness();
if ( nextColCutE>nextRowCutE ) {
colCutIndex_++;
cutP_=cutsPtr_->colCutPtr(colCutIndex_);
}
else {
rowCutIndex_++;
cutP_=cutsPtr_->rowCutPtr(rowCutIndex_);
}
}
return *this;
}
/* Insert a row cut unless it is a duplicate (CoinAbsFltEq)*/
void
OsiCuts::insertIfNotDuplicate( OsiRowCut & rc , CoinAbsFltEq treatAsSame)
{
double newLb = rc.lb();
double newUb = rc.ub();
CoinPackedVector vector = rc.row();
int numberElements =vector.getNumElements();
int * newIndices = vector.getIndices();
double * newElements = vector.getElements();
CoinSort_2(newIndices,newIndices+numberElements,newElements);
bool notDuplicate=true;
int numberRowCuts = sizeRowCuts();
for ( int i =0; i<numberRowCuts;i++) {
const OsiRowCut * cutPtr = rowCutPtr(i);
if (cutPtr->row().getNumElements()!=numberElements)
continue;
if (!treatAsSame(cutPtr->lb(),newLb))
continue;
if (!treatAsSame(cutPtr->ub(),newUb))
continue;
const CoinPackedVector * thisVector = &(cutPtr->row());
const int * indices = thisVector->getIndices();
const double * elements = thisVector->getElements();
int j;
for(j=0;j<numberElements;j++) {
if (indices[j]!=newIndices[j])
break;
if (!treatAsSame(elements[j],newElements[j]))
break;
}
if (j==numberElements) {
notDuplicate=false;
break;
}
}
if (notDuplicate) {
OsiRowCut * newCutPtr = new OsiRowCut();
newCutPtr->setLb(newLb);
newCutPtr->setUb(newUb);
newCutPtr->setRow(vector);
rowCutPtrs_.push_back(newCutPtr);
}
}
/* Insert a row cut unless it is a duplicate (CoinRelFltEq)*/
void
OsiCuts::insertIfNotDuplicate( OsiRowCut & rc , CoinRelFltEq treatAsSame)
{
double newLb = rc.lb();
double newUb = rc.ub();
CoinPackedVector vector = rc.row();
int numberElements =vector.getNumElements();
int * newIndices = vector.getIndices();
double * newElements = vector.getElements();
CoinSort_2(newIndices,newIndices+numberElements,newElements);
bool notDuplicate=true;
int numberRowCuts = sizeRowCuts();
for ( int i =0; i<numberRowCuts;i++) {
const OsiRowCut * cutPtr = rowCutPtr(i);
if (cutPtr->row().getNumElements()!=numberElements)
continue;
if (!treatAsSame(cutPtr->lb(),newLb))
continue;
if (!treatAsSame(cutPtr->ub(),newUb))
continue;
const CoinPackedVector * thisVector = &(cutPtr->row());
const int * indices = thisVector->getIndices();
const double * elements = thisVector->getElements();
int j;
for(j=0;j<numberElements;j++) {
if (indices[j]!=newIndices[j])
break;
if (!treatAsSame(elements[j],newElements[j]))
break;
}
if (j==numberElements) {
notDuplicate=false;
break;
}
}
if (notDuplicate) {
OsiRowCut * newCutPtr = new OsiRowCut();
newCutPtr->setLb(newLb);
newCutPtr->setUb(newUb);
newCutPtr->setRow(vector);
rowCutPtrs_.push_back(newCutPtr);
}
}