// Copyright (C) 2000, International Business Machines // Corporation and others. All Rights Reserved. #if defined(_MSC_VER) // Turn off compiler warning about long names # pragma warning(disable:4786) #endif #include #include #include "CoinFinite.hpp" #include "CoinHelperFunctions.hpp" #include "CoinIndexedVector.hpp" #include "CoinTypes.hpp" //############################################################################# void CoinIndexedVector::clear() { if (!packedMode_) { if (3*nElements_=COIN_INDEXED_TINY_ELEMENT) { elements_[indexValue]=elems[i]; indices_[nElements_++]=indexValue; } } } //############################################################################# /** Access the i'th element of the full storage vector. */ double & CoinIndexedVector::operator[](int index) const { assert (!packedMode_); if ( index >= capacity_ ) throw CoinError("index >= capacity()", "[]", "CoinIndexedVector"); if ( index < 0 ) throw CoinError("index < 0" , "[]", "CoinIndexedVector"); double * where = elements_ + index; return *where; } //############################################################################# void CoinIndexedVector::setElement(int index, double element) { if ( index >= nElements_ ) throw CoinError("index >= size()", "setElement", "CoinIndexedVector"); if ( index < 0 ) throw CoinError("index < 0" , "setElement", "CoinIndexedVector"); elements_[indices_[index]] = element; } //############################################################################# void CoinIndexedVector::insert( int index, double element ) { if ( index < 0 ) throw CoinError("index < 0" , "setElement", "CoinIndexedVector"); if (index >= capacity_) reserve(index+1); if (elements_[index]) throw CoinError("Index already exists", "insert", "CoinIndexedVector"); indices_[nElements_++] = index; elements_[index] = element; } //############################################################################# void CoinIndexedVector::add( int index, double element ) { if ( index < 0 ) throw CoinError("index < 0" , "setElement", "CoinIndexedVector"); if (index >= capacity_) reserve(index+1); if (elements_[index]) { element += elements_[index]; if (fabs(element)>= COIN_INDEXED_TINY_ELEMENT) { elements_[index] = element; } else { elements_[index] = COIN_INDEXED_REALLY_TINY_ELEMENT; } } else if (fabs(element)>= COIN_INDEXED_TINY_ELEMENT) { indices_[nElements_++] = index; assert (nElements_<=capacity_); elements_[index] = element; } } //############################################################################# int CoinIndexedVector::clean( double tolerance ) { int number = nElements_; int i; nElements_=0; assert(!packedMode_); for (i=0;i=tolerance) { indices_[nElements_++]=indexValue; } else { elements_[indexValue]=0.0; } } return nElements_; } //############################################################################# // For debug check vector is clear i.e. no elements void CoinIndexedVector::checkClear() { #ifndef NDEBUG assert(!nElements_); assert(!packedMode_); int i; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { elements_[indexValue]=celem[i]; indices_[nElements_++]=indexValue; } } } if (needClean) { // go through again int size=nElements_; nElements_=0; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { indices_[nElements_++]=indexValue; } else { elements_[indexValue]=0.0; } } } if (numberDuplicates) throw CoinError("duplicate index", "append", "CoinIndexedVector"); } #endif //############################################################################# void CoinIndexedVector::swap(int i, int j) { if ( i >= nElements_ ) throw CoinError("index i >= size()","swap","CoinIndexedVector"); if ( i < 0 ) throw CoinError("index i < 0" ,"swap","CoinIndexedVector"); if ( j >= nElements_ ) throw CoinError("index j >= size()","swap","CoinIndexedVector"); if ( j < 0 ) throw CoinError("index j < 0" ,"swap","CoinIndexedVector"); // Swap positions i and j of the // indices array int isave = indices_[i]; indices_[i] = indices_[j]; indices_[j] = isave; } //############################################################################# void CoinIndexedVector::truncate( int n ) { reserve(n); } //############################################################################# void CoinIndexedVector::operator+=(double value) { assert (!packedMode_); int i,indexValue; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) elements_[indexValue] = newValue; else elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; } } //----------------------------------------------------------------------------- void CoinIndexedVector::operator-=(double value) { assert (!packedMode_); int i,indexValue; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) elements_[indexValue] = newValue; else elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; } } //----------------------------------------------------------------------------- void CoinIndexedVector::operator*=(double value) { assert (!packedMode_); int i,indexValue; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) elements_[indexValue] = newValue; else elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; } } //----------------------------------------------------------------------------- void CoinIndexedVector::operator/=(double value) { assert (!packedMode_); int i,indexValue; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) elements_[indexValue] = newValue; else elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT; } } //############################################################################# void CoinIndexedVector::reserve(int n) { int i; // don't make allocated space smaller but do take off values if ( n < capacity_ ) { if (n<0) throw CoinError("negative capacity", "reserve", "CoinIndexedVector"); int nNew=0; for (i=0;icapacity_) { // save pointers to existing data int * tempIndices = indices_; double * tempElements = elements_; double * delTemp = elements_-offset_; // allocate new space int nPlus; if (sizeof(int)==4*sizeof(char)) nPlus=(n+3)>>2; else nPlus=(n+7)>>4; indices_ = new int [n+nPlus]; CoinZeroN(indices_+n,nPlus); // align on 64 byte boundary double * temp = new double [n+7]; offset_ = 0; CoinInt64 xx = reinterpret_cast(temp); int iBottom = static_cast(xx & 63); if (iBottom) offset_ = (64-iBottom)>>3; elements_ = temp + offset_;; // copy data to new space // and zero out part of array if (nElements_ > 0) { CoinMemcpyN(tempIndices, nElements_, indices_); CoinMemcpyN(tempElements, capacity_, elements_); CoinZeroN(elements_+capacity_,n-capacity_); } else { CoinZeroN(elements_,n); } capacity_ = n; // free old data if (tempElements) delete [] delTemp; delete [] tempIndices; } } //############################################################################# CoinIndexedVector::CoinIndexedVector () : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { } CoinIndexedVector::CoinIndexedVector (int size) : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { // Get space reserve(size); } //----------------------------------------------------------------------------- CoinIndexedVector::CoinIndexedVector(int size, const int * inds, const double * elems) : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { gutsOfSetVector(size, inds, elems); } //----------------------------------------------------------------------------- CoinIndexedVector::CoinIndexedVector(int size, const int * inds, double value) : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { gutsOfSetConstant(size, inds, value); } //----------------------------------------------------------------------------- CoinIndexedVector::CoinIndexedVector(int size, const double * element) : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { setFull(size, element); } //----------------------------------------------------------------------------- #ifndef CLP_NO_VECTOR CoinIndexedVector::CoinIndexedVector(const CoinPackedVectorBase & rhs) : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { gutsOfSetVector(rhs.getNumElements(), rhs.getIndices(), rhs.getElements()); } #endif //----------------------------------------------------------------------------- CoinIndexedVector::CoinIndexedVector(const CoinIndexedVector & rhs) : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { if (!rhs.packedMode_) gutsOfSetVector(rhs.capacity_,rhs.nElements_, rhs.indices_, rhs.elements_); else gutsOfSetPackedVector(rhs.capacity_,rhs.nElements_, rhs.indices_, rhs.elements_); } //----------------------------------------------------------------------------- CoinIndexedVector::CoinIndexedVector(const CoinIndexedVector * rhs) : indices_(NULL), elements_(NULL), nElements_(0), capacity_(0), offset_(0), packedMode_(false) { if (!rhs->packedMode_) gutsOfSetVector(rhs->capacity_,rhs->nElements_, rhs->indices_, rhs->elements_); else gutsOfSetPackedVector(rhs->capacity_,rhs->nElements_, rhs->indices_, rhs->elements_); } //----------------------------------------------------------------------------- CoinIndexedVector::~CoinIndexedVector () { delete [] indices_; if (elements_) delete [] (elements_-offset_); } //############################################################################# //############################################################################# /// Return the sum of two indexed vectors CoinIndexedVector CoinIndexedVector::operator+( const CoinIndexedVector& op2) { assert (!packedMode_); int i; int nElements=nElements_; int capacity = CoinMax(capacity_,op2.capacity_); CoinIndexedVector newOne(*this); newOne.reserve(capacity); bool needClean=false; // new one now can hold everything so just modify old and add new for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { newOne.elements_[indexValue]=value; newOne.indices_[nElements++]=indexValue; } } else { value += oldValue; newOne.elements_[indexValue]=value; if (fabs(value)=COIN_INDEXED_TINY_ELEMENT) { newOne.indices_[newOne.nElements_++]=indexValue; } else { newOne.elements_[indexValue]=0.0; } } } return newOne; } /// Return the difference of two indexed vectors CoinIndexedVector CoinIndexedVector::operator-( const CoinIndexedVector& op2) { assert (!packedMode_); int i; int nElements=nElements_; int capacity = CoinMax(capacity_,op2.capacity_); CoinIndexedVector newOne(*this); newOne.reserve(capacity); bool needClean=false; // new one now can hold everything so just modify old and add new for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { newOne.elements_[indexValue]=-value; newOne.indices_[nElements++]=indexValue; } } else { value = oldValue-value; newOne.elements_[indexValue]=value; if (fabs(value)=COIN_INDEXED_TINY_ELEMENT) { newOne.indices_[newOne.nElements_++]=indexValue; } else { newOne.elements_[indexValue]=0.0; } } } return newOne; } /// Return the element-wise product of two indexed vectors CoinIndexedVector CoinIndexedVector::operator*( const CoinIndexedVector& op2) { assert (!packedMode_); int i; int nElements=nElements_; int capacity = CoinMax(capacity_,op2.capacity_); CoinIndexedVector newOne(*this); newOne.reserve(capacity); bool needClean=false; // new one now can hold everything so just modify old and add new for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { newOne.indices_[newOne.nElements_++]=indexValue; } else { newOne.elements_[indexValue]=0.0; } } } return newOne; } /// Return the element-wise ratio of two indexed vectors CoinIndexedVector CoinIndexedVector::operator/ (const CoinIndexedVector& op2) { assert (!packedMode_); // I am treating 0.0/0.0 as 0.0 int i; int nElements=nElements_; int capacity = CoinMax(capacity_,op2.capacity_); CoinIndexedVector newOne(*this); newOne.reserve(capacity); bool needClean=false; // new one now can hold everything so just modify old and add new for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { newOne.indices_[newOne.nElements_++]=indexValue; } else { newOne.elements_[indexValue]=0.0; } } } return newOne; } // The sum of two indexed vectors void CoinIndexedVector::operator+=(const CoinIndexedVector& op2) { // do slowly at first *this = *this + op2; } // The difference of two indexed vectors void CoinIndexedVector::operator-=( const CoinIndexedVector& op2) { // do slowly at first *this = *this - op2; } // The element-wise product of two indexed vectors void CoinIndexedVector::operator*=(const CoinIndexedVector& op2) { // do slowly at first *this = *this * op2; } // The element-wise ratio of two indexed vectors (0.0/0.0 => 0.0) (0 vanishes) void CoinIndexedVector::operator/=(const CoinIndexedVector& op2) { // do slowly at first *this = *this / op2; } //############################################################################# void CoinIndexedVector::sortDecrIndex() { // Should replace with std sort double * elements = new double [nElements_]; CoinZeroN (elements,nElements_); CoinSort_2(indices_, indices_ + nElements_, elements, CoinFirstGreater_2()); delete [] elements; } void CoinIndexedVector::sortIncrElement() { double * elements = new double [nElements_]; int i; for (i=0;i()); delete [] elements; } void CoinIndexedVector::sortDecrElement() { double * elements = new double [nElements_]; int i; for (i=0;i()); delete [] elements; } //############################################################################# void CoinIndexedVector::gutsOfSetVector(int size, const int * inds, const double * elems) { if (size<0) throw CoinError("negative number of indices", "setVector", "CoinIndexedVector"); assert(!packedMode_); // find largest int i; int maxIndex=-1; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { indices_[nElements_++]=indexValue; elements_[indexValue]=elems[i]; } } else { numberDuplicates++; elements_[indexValue] += elems[i] ; if (fabs(elements_[indexValue])=COIN_INDEXED_TINY_ELEMENT) { indices_[nElements_++]=indexValue; } else { elements_[indexValue]=0.0; } } } if (numberDuplicates) throw CoinError("duplicate index", "setVector", "CoinIndexedVector"); } //############################################################################# void CoinIndexedVector::gutsOfSetVector(int size, int numberIndices, const int * inds, const double * elems) { assert(!packedMode_); int i; reserve(size); if (numberIndices<0) throw CoinError("negative number of indices", "setVector", "CoinIndexedVector"); nElements_ = 0; // elements_ array is all zero bool needClean=false; int numberDuplicates=0; for (i=0;i=size) throw CoinError("too large an index", "setVector", "CoinIndexedVector"); if (elements_[indexValue]) { numberDuplicates++; elements_[indexValue] += elems[indexValue] ; if (fabs(elements_[indexValue])=COIN_INDEXED_TINY_ELEMENT) { elements_[indexValue]=elems[indexValue]; indices_[nElements_++]=indexValue; } } } if (needClean) { // go through again size=nElements_; nElements_=0; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { indices_[nElements_++]=indexValue; } else { elements_[indexValue]=0.0; } } } if (numberDuplicates) throw CoinError("duplicate index", "setVector", "CoinIndexedVector"); } //----------------------------------------------------------------------------- void CoinIndexedVector::gutsOfSetPackedVector(int size, int numberIndices, const int * inds, const double * elems) { packedMode_=true; int i; reserve(size); if (numberIndices<0) throw CoinError("negative number of indices", "setVector", "CoinIndexedVector"); nElements_ = 0; // elements_ array is all zero // Does not check for duplicates for (i=0;i=size) throw CoinError("too large an index", "setVector", "CoinIndexedVector"); if (fabs(elems[i])>=COIN_INDEXED_TINY_ELEMENT) { elements_[nElements_]=elems[i]; indices_[nElements_++]=indexValue; } } } //----------------------------------------------------------------------------- void CoinIndexedVector::gutsOfSetConstant(int size, const int * inds, double value) { assert(!packedMode_); if (size<0) throw CoinError("negative number of indices", "setConstant", "CoinIndexedVector"); // find largest int i; int maxIndex=-1; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { elements_[indexValue] += value; indices_[nElements_++]=indexValue; } } else { numberDuplicates++; elements_[indexValue] += value ; if (fabs(elements_[indexValue])=COIN_INDEXED_TINY_ELEMENT) { indices_[nElements_++]=indexValue; } else { elements_[indexValue]=0.0; } } } if (numberDuplicates) throw CoinError("duplicate index", "setConstant", "CoinIndexedVector"); } //############################################################################# // Append a CoinIndexedVector to the end void CoinIndexedVector::append(const CoinIndexedVector & caboose) { const int cs = caboose.getNumElements(); const int * cind = caboose.getIndices(); const double * celem = caboose.denseVector(); int maxIndex=-1; int i; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { elements_[indexValue]=celem[indexValue]; indices_[nElements_++]=indexValue; } } } if (needClean) { // go through again int size=nElements_; nElements_=0; for (i=0;i=COIN_INDEXED_TINY_ELEMENT) { indices_[nElements_++]=indexValue; } else { elements_[indexValue]=0.0; } } } if (numberDuplicates) throw CoinError("duplicate index", "append", "CoinIndexedVector"); } #ifndef CLP_NO_VECTOR /* Equal. Returns true if vectors have same length and corresponding element of each vector is equal. */ bool CoinIndexedVector::operator==(const CoinPackedVectorBase & rhs) const { const int cs = rhs.getNumElements(); const int * cind = rhs.getIndices(); const double * celem = rhs.getElements(); if (nElements_!=cs) return false; int i; bool okay=true; for (i=0;i=tolerance) indices[number++] = i; else elements_[i]=0.0; } } nElements_ += number; return number; } // These pack down int CoinIndexedVector::cleanAndPack( double tolerance ) { int number = nElements_; int i; nElements_=0; assert(!packedMode_); for (i=0;i=tolerance) { elements_[nElements_]=value; indices_[nElements_++]=indexValue; } } packedMode_=true; return nElements_; } // These pack down int CoinIndexedVector::cleanAndPackSafe( double tolerance ) { int number = nElements_; if (number) { int i; nElements_=0; assert(!packedMode_); double * temp=NULL; bool gotMemory; if (number*3(tempC); CoinInt64 iBottom = xx & 7; if (iBottom) tempC += 8-iBottom; temp = (double *) tempC; xx = reinterpret_cast(temp); iBottom = xx & 7; assert(!iBottom); } else { // might be better to do complete scan gotMemory=true; temp = new double[number]; } for (i=0;i=tolerance) { temp[nElements_]=value; indices_[nElements_++]=indexValue; } } CoinMemcpyN(temp,nElements_,elements_); if (gotMemory) delete [] temp; packedMode_=true; } return nElements_; } // Scan dense region and set up indices int CoinIndexedVector::scanAndPack() { nElements_=0; return scanAndPack(0,capacity_); } // Scan dense region from start to < end and set up indices int CoinIndexedVector::scanAndPack(int start, int end) { assert(!packedMode_); end = CoinMin(end,capacity_); start = CoinMax(start,0); int i; int number = 0; int * indices = indices_+nElements_; for (i=start;i=tolerance) { elements_[number]=value; indices[number++] = i; } } nElements_ += number; packedMode_=true; return number; } // This is mainly for testing - goes from packed to indexed void CoinIndexedVector::expand() { if (nElements_&&packedMode_) { double * temp = new double[capacity_]; int i; for (i=0;i0&&array_)||!array_); memset (array_,0,size_); } static char * mallocArray(long size) { if (size>0) { char * array = new char [size]; return array; } else { return NULL; } } static void freeArray(void * array) { char * charArray = (char *) array; delete [] charArray; } // Conditionally gets new array char * CoinArrayWithLength::conditionalNew(long sizeWanted) { if (size_==-1) { freeArray(array_); array_ = mallocArray(sizeWanted); } else { setCapacity(); if (sizeWanted>size_) { freeArray(array_); size_ = (int) (sizeWanted*1.01)+64; array_ = mallocArray(size_); } } return array_; } // Conditionally deletes void CoinArrayWithLength::conditionalDelete() { if (size_==-1) { freeArray(array_); array_=NULL; } else if (size_>=0) { size_ = -size_-2; } } /* Copy constructor. */ CoinArrayWithLength::CoinArrayWithLength(const CoinArrayWithLength & rhs) { assert (rhs.getCapacity()>=0); size_=rhs.size_; array_ = mallocArray(getCapacity()); if (size_>0) memcpy(array_,rhs.array_,size_); } /* Copy constructor.2 */ CoinArrayWithLength::CoinArrayWithLength(const CoinArrayWithLength * rhs) { assert (rhs->getCapacity()>=0); size_=rhs->size_; array_ = mallocArray(getCapacity()); if (size_>0) memcpy(array_,rhs->array_,size_); } /* Assignment operator. */ CoinArrayWithLength & CoinArrayWithLength::operator=(const CoinArrayWithLength & rhs) { if (this != &rhs) { assert (rhs.size_!=-1||!rhs.array_); if (rhs.size_==-1) { freeArray(array_); array_=NULL; size_=-1; } else { int capacity = getCapacity(); int rhsCapacity = rhs.getCapacity(); if (capacity0) memcpy(array_,rhs.array_,size_); } } return *this; } /* Assignment with length (if -1 use internal length) */ void CoinArrayWithLength::copy(const CoinArrayWithLength & rhs, int numberBytes) { if (numberBytes==-1||numberBytes<=rhs.getCapacity()) { CoinArrayWithLength::operator=(rhs); } else { assert (numberBytes>=0); if (size_==-1) { freeArray(array_); array_=NULL; } else { size_=-1; } if (rhs.size_>=0) size_ = numberBytes; array_ = mallocArray(numberBytes); if (rhs.array_) memcpy(array_,rhs.array_,numberBytes); } } /* Assignment with length - does not copy */ void CoinArrayWithLength::allocate(const CoinArrayWithLength & rhs, int numberBytes) { if (numberBytes==-1||numberBytes<=rhs.getCapacity()) { assert (rhs.size_!=-1||!rhs.array_); if (rhs.size_==-1) { freeArray(array_); array_=NULL; size_=-1; } else { int capacity = getCapacity(); int rhsCapacity = rhs.getCapacity(); if (capacity=0); if (size_==-1) { freeArray(array_); array_=NULL; } else { size_=-1; } if (rhs.size_>=0) size_ = numberBytes; array_ = mallocArray(numberBytes); } } // Does what is needed to set persistence void CoinArrayWithLength::setPersistence(int flag,int currentLength) { if (flag) { if (size_==-1) { if (currentLength&&array_) { size_=currentLength; } else { size_=0; freeArray(array_); array_=NULL; } } } else { size_=-1; } } // Swaps memory between two members void CoinArrayWithLength::swap(CoinArrayWithLength & other) { assert (size_==other.size_); char * swapArray = other.array_; other.array_=array_; array_=swapArray; int swapSize = other.size_; other.size_=size_; size_=swapSize; } // Extend a persistent array keeping data (size in bytes) void CoinArrayWithLength::extend(int newSize) { //assert (newSize>=getCapacity()&&getCapacity()>=0); assert (size_>=0); // not much point otherwise if (newSize>size_) { char * temp = mallocArray(newSize); memcpy(temp,array_,size_); freeArray(array_); array_=temp; size_=newSize; } }