#ifndef _EVECTOR_BASICVECTOR_TCC #define _EVECTOR_BASICVECTOR_TCC #include #include #include #include "core/basics/Exception.h" #define _THROW_EVector(string) fthrow(Exception, string) #include "core/vector/ippwrapper.h" #include "core/vector/VectorT.h" #include "core/vector/MatrixT.h" #include namespace NICE { template inline VectorT::VectorT() { setDataPointer(NULL, 0, false); } template inline VectorT::VectorT(const size_t size) { setDataPointer(new ElementType[size], size, false); } template inline VectorT::VectorT(const size_t size, const ElementType& element) { setDataPointer(new ElementType[size], size, false); ippsSet(element, getDataPointer(), size); } template inline VectorT::VectorT(const ElementType* _data, const size_t size) { setDataPointer(new ElementType[size], size, false); ippsCopy(_data, getDataPointer(), size); } template inline VectorT::VectorT(ElementType* _data, const size_t size, const VectorBase::Mode mode) { switch (mode) { case external: setDataPointer(_data, size, true); break; case copy: setDataPointer(new ElementType[size], size, false); ippsCopy(_data, getDataPointer(), size); break; default: setDataPointer(NULL, 0, false); _THROW_EVector("Unknown Mode-enum."); } } template VectorT::VectorT(const std::vector& v) { setDataPointer(new ElementType[v.size()], v.size(), false); ippsCopy(&(*v.begin()), getDataPointer(), v.size()); } template VectorT::VectorT(std::istream& input, const bool & AwAFormat) { if (AwAFormat) //count, how many elements the vector contains { dataSize = 0; while (true) { ElementType c; input >> c; if (input.eof()) { break; } dataSize++; } //reset our stream to the beginning of the file input.clear() ; input.seekg(0, std::ios::beg) ; } else input >> dataSize; setDataPointer(new ElementType[dataSize], dataSize, false); if (AwAFormat) { int i = -1; while (true) { if (input.eof()) { break; // FIXME check if end of stream or followed by whitespace } i++; //ElementType c; //input >> c; //data[i] = c; input >> getDataPointer()[i]; } } else { char c; input >> c; if (c != '<') { input.putback ( c ); } int i = -1; while (true) { ws(input); if (input.peek() == int('>')) { std::string s; input >> s; break; } ++i; if (i >= int(dataSize)) { _THROW_EVector("syntax error 2 reading VectorT"); } input >> getDataPointer()[i]; } } } template VectorT::VectorT(const VectorT& v) { setDataPointer(new ElementType[v.dataSize], v.dataSize, false); ippsCopy(v.getDataPointer(), getDataPointer(), dataSize); } #ifdef NICE_USELIB_LINAL template inline VectorT::VectorT(const LinAl::VectorC& v) { setDataPointer(new ElementType[v.size()], v.size(), false); for (unsigned int i = 0; i < size(); i++) { (*this)(i) = v(i); } } template inline VectorT& VectorT::operator=(const LinAl::VectorCC& v) { if (size() == 0 && !externalStorage && getDataPointer() == NULL) { setDataPointer(new ElementType[v.size()], v.size(), false); } else if (this->size() != (unsigned int) v.size()) { this->resize(v.size()); } for (unsigned int i = 0; i < size(); i++) { (*this)[i] = v(i); } return *this; } #endif // NICE_USELIB_LINAL template inline VectorT::~VectorT() { if (!externalStorage && data != NULL) { delete[] data; setDataPointer(NULL, 0, false); } } template void VectorT::resize(size_t size) { if(dataSize==size) return; // resize(0) simply means we want to empty the vector if(size==0) { ElementType *tmp = getDataPointer(); if ( tmp != NULL ) delete [] tmp; setDataPointer(NULL,0, false); } if(externalStorage) { if(size void VectorT::append( const VectorT & v ) { unsigned int oldsize = size(); resize ( oldsize + v.size() ); VectorT subvec = getRangeRef(oldsize, size()-1); subvec = v; } template void VectorT::append( const ElementType & v ) { unsigned int oldsize = size(); resize ( oldsize + 1 ); (*this)[oldsize] = v; } template VectorT VectorT::getRange ( const ptrdiff_t i, const ptrdiff_t j ) const { const ElementType *subDataPtr = getDataPointer() + i; VectorT subvec ( subDataPtr, j-i+1 ); return subvec; } template VectorT VectorT::getRangeRef ( const ptrdiff_t i, const ptrdiff_t j ) { ElementType *subDataPtr = getDataPointer() + i; VectorT subvec ( subDataPtr, j-i+1, VectorBase::external ); return subvec; } template void VectorT::clear(void) { if (externalStorage) { _THROW_EVector("Cannot clear VectorT (external storage used)"); } if (data != NULL) { delete[] data; setDataPointer(NULL, 0, false); } } template inline const VectorT* VectorT::createConst(const ElementType* _data, const size_t size) { VectorT* result = new VectorT; result->setConstDataPointer(_data, size); return result; } template const ElementType& VectorT::operator()(const ptrdiff_t i) const { if((ptrdiff_t)dataSize<=i||i<0) { //std::__throw_out_of_range("VectorT () access out of range"); throw std::out_of_range("VectorT () access out of range"); } return constData[i]; } template ElementType& VectorT::operator()(const ptrdiff_t i) { if((ptrdiff_t)dataSize<=i||i<0) { //std::__throw_out_of_range("VectorT () access out of range"); throw std::out_of_range("VectorT () access out of range"); } return data[i]; } template inline bool VectorT::operator==(const VectorT& v) const { if (size() != v.size()) { throw std::invalid_argument("VectorT::operator==(): v.size() != size()"); } else if (size() == 0) { return true; } for (unsigned int i = 0; i < size(); i++) { if(!(operator[](i) == v[i])) return false; } return true; } template inline bool VectorT::operator!=(const VectorT& v) const { if (size() != v.size()) { throw std::invalid_argument("VectorT::operator!=(): v.size() != size()"); } else if (size() == 0) { return false; } for (unsigned int i = 0; i < size(); i++) { if(!(operator[](i) == v[i])) return true; } return false; } template void VectorT::multiply(const MatrixT& a, const VectorT& v, bool atranspose) { size_t arows, acols; if(atranspose) { arows=a.cols(); acols=a.rows(); } else { arows=a.rows(); acols=a.cols(); } if (size() == 0) resize(arows); if (arows != size() || acols != v.size()) _THROW_EVector("Matrix multiplication: inconsistent sizes."); #ifdef NICE_USELIB_IPP size_t tsize=sizeof(ElementType); IppStatus ret; if(atranspose) { ret = ippmMul_mv(a.getDataPointer(), a.rows()*tsize, tsize, a.rows(), a.cols(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } else { ret = ippmMul_tv(a.getDataPointer(), a.rows()*tsize, tsize, a.rows(), a.cols(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); #else #pragma omp parallel for // FIXME not very efficient for (int i = 0; i < int(arows); i++) { ElementType sum = ElementType(0); for (unsigned int k = 0; k < acols; k++) { ElementType ela = atranspose ? a(k, i) : a(i, k); sum += ela * v(k); } (*this)(i) = sum; } #endif } template void VectorT::multiply(const VectorT& v, const RowMatrixT& a, bool atranspose) { size_t arows, acols; if(atranspose) { arows=a.cols(); acols=a.rows(); } else { arows=a.rows(); acols=a.cols(); } if (size() == 0) resize(acols); if (acols != size() || arows != v.size()) _THROW_EVector("Matrix multiplication: inconsistent sizes."); #ifdef NICE_USELIB_IPP size_t tsize=sizeof(ElementType); IppStatus ret; if(atranspose) { ret = ippmMul_mv(a.getDataPointer(), a.cols()*tsize, tsize, a.cols(), a.rows(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } else { ret = ippmMul_tv(a.getDataPointer(), a.cols()*tsize, tsize, a.cols(), a.rows(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); #else #pragma omp parallel for // FIXME not very efficient for (int i = 0; i < int(acols); i++) { ElementType sum = ElementType(0); for (unsigned int k = 0; k < arows; k++) { ElementType ela = atranspose ? a(i, k) : a(k, i); sum += v(k) * ela; } (*this)(i) = sum; } #endif } template void VectorT::multiply(const RowMatrixT& a, const VectorT& v, bool atranspose) { size_t arows, acols; if(atranspose) { arows=a.cols(); acols=a.rows(); } else { arows=a.rows(); acols=a.cols(); } if (size() == 0) resize(arows); if (arows != size() || acols != v.size()) _THROW_EVector("Matrix multiplication: inconsistent sizes."); #ifdef NICE_USELIB_IPP size_t tsize=sizeof(ElementType); IppStatus ret; if(atranspose) { ret = ippmMul_tv(a.getDataPointer(), a.cols()*tsize, tsize, a.cols(), a.rows(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } else { ret = ippmMul_mv(a.getDataPointer(), a.cols()*tsize, tsize, a.cols(), a.rows(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); #else // FIXME not very efficient ElementType ela; for (unsigned int i = 0; i < arows; i++) { ElementType sum = ElementType(0); for (unsigned int k = 0; k < acols; k++) { ela = atranspose ? a(k, i) : a(i, k); sum += ela * v(k); } (*this)(i) = sum; } #endif } template void VectorT::multiply(const VectorT& v, const MatrixT& a, bool atranspose) { size_t arows, acols; if(atranspose) { arows=a.cols(); acols=a.rows(); } else { arows=a.rows(); acols=a.cols(); } if (size() == 0) resize(acols); if (acols != size() || arows != v.size()) _THROW_EVector("Matrix multiplication: inconsistent sizes."); #ifdef NICE_USELIB_IPP size_t tsize=sizeof(ElementType); IppStatus ret; if(atranspose) { ret = ippmMul_tv(a.getDataPointer(), a.rows()*tsize, tsize, a.rows(), a.cols(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } else { ret = ippmMul_mv(a.getDataPointer(), a.rows()*tsize, tsize, a.rows(), a.cols(), v.getDataPointer(), tsize, v.size(), this->getDataPointer(), tsize); } if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); #else // FIXME not very efficient ElementType ela; for (unsigned int i = 0; i < acols; i++) { ElementType sum = ElementType(0); for (unsigned int k = 0; k < arows; k++) { ela = atranspose ? a(i, k) : a(k, i); sum += v(k) * ela; } (*this)(i) = sum; } #endif } template inline ElementType VectorT::scalarProduct( const VectorT& v) const { if (size() != v.size()) { throw std::invalid_argument("VectorT::scalarProduct(): v.size() != size()"); } else if (size() == 0) { throw std::invalid_argument("VectorT::scalarProduct(): size() == 0"); } ElementType result; IppStatus ret = ippsDotProd(getDataPointer(),v.getDataPointer(),dataSize,&result); if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); return result; } template inline ElementType VectorT::Median() const { VectorT sorted(*this); sorted.sortAscend(); return sorted[dataSize/2]; } #define _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(_IppName,_Name) \ template \ inline ElementType \ VectorT::_Name() const { \ ElementType result=0; \ IppStatus ret = ipps##_IppName(getDataPointer(), dataSize, &result); \ if(ret!=ippStsNoErr) \ _THROW_EVector(ippGetStatusString(ret)); \ return result; \ } #ifndef DISABLE_IPP_MAXMIN // in the current version of valgrind, valgrind // does not recognize some cpu operations used // in the IPP routines of ippMax and ippMin _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(Max,Max) _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(Min,Min) #else template inline ElementType VectorT::Max() const { ElementType maximum = - std::numeric_limits::max(); for ( uint i = 0 ; i < size() ; i++ ) if ( (*this)(i) > maximum ) maximum = (*this)(i); return maximum; } template inline ElementType VectorT::Min() const { ElementType minimum = std::numeric_limits::max(); for ( uint i = 0 ; i < size() ; i++ ) if ( (*this)(i) < minimum ) minimum = (*this)(i); return minimum; } #endif _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(Sum,Sum) _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(Mean,Mean) _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(StdDev,StdDev) #ifdef NICE_USELIB_IPP _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(Norm_Inf,normInf) #else // The previous standard implementation didn't work for negative values! template inline ElementType VectorT::normInf() const { ElementType zero ( 0 ); ElementType minusOne ( -1 ); ElementType infNorm = zero; for ( uint i = 0 ; i < size() ; i++ ) { if ( (*this)(i) < zero ) //negative entry { if ( ((*this)(i) * minusOne) > infNorm) infNorm = ((*this)(i) * minusOne); } else //positive entry { if ( (*this)(i) > infNorm) infNorm = (*this)(i) ; } } return infNorm; } #endif _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(Norm_L1,normL1) _DEFINE_EVECTOR_CONSTVOIDELEMENTFUNC(Norm_L2,normL2) #define _DEFINE_EVECTOR_VOIDIPFUNC(_IppName,_Name) \ template \ inline void VectorT::_Name() { \ IppStatus ret = ipps##_IppName(getDataPointer(), dataSize); \ if(ret!=ippStsNoErr) \ _THROW_EVector(ippGetStatusString(ret)); \ } _DEFINE_EVECTOR_VOIDIPFUNC(Abs_I,absInplace) #define _DEFINE_EVECTOR_VOIDEVECTORFUNC(_IppName,_Name) \ template \ inline VectorT VectorT::_Name() const { \ VectorT result(dataSize); \ IppStatus ret = ipps##_IppName(getDataPointer(),result.getDataPointer(), dataSize); \ if(ret!=ippStsNoErr) \ _THROW_EVector(ippGetStatusString(ret)); \ return result; \ } _DEFINE_EVECTOR_VOIDEVECTORFUNC(Abs,abs) template inline int VectorT::MaxIndex() const { int result; ElementType elem; IppStatus ret = ippsMaxIndx(getDataPointer(), dataSize, &elem, &result); if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); return result; } template inline int VectorT::MinIndex() const { int result; ElementType elem; IppStatus ret = ippsMinIndx(getDataPointer(), dataSize, &elem, &result); if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); return result; } template inline VectorT VectorT::UniformRandom(const size_t size, ElementType min, ElementType max, unsigned int seed) { VectorT result(size); IppStatus ret = ippsRandUniform_Direct(result.getDataPointer(),size,min,max,&seed); if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); return result; } template inline VectorT VectorT::UniformRandom(const size_t size, ElementType min, ElementType max) { VectorT result(size); for (uint i = 0 ; i < size ; i++ ) result[i] = (ElementType) ( randDouble((double)(max-min)) + (double)min ); return result; } template inline VectorT VectorT::GaussRandom(const size_t size, ElementType mean, ElementType stdev, unsigned int seed) { VectorT result(size); #ifdef NICE_USELIB_IPP IppStatus ret = ippsRandGauss_Direct(result.getDataPointer(),size,mean,stdev,&seed); if(ret!=ippStsNoErr) _THROW_EVector(ippGetStatusString(ret)); #else initRand ( true, seed ); for ( int i = 0 ; i < size ; i++ ) result[i] = randGaussDouble ( stdev ) + mean; #endif return result; } template inline VectorT VectorT::GaussRandom(const size_t size, ElementType mean, ElementType stdev) { VectorT result(size); for ( uint i = 0 ; i < size ; i++ ) result[i] = randGaussDouble ( stdev ) + mean; return result; } template inline VectorT& VectorT::operator=(const VectorT& v) { if (dataSize == 0 && !externalStorage && getDataPointer() == NULL) { setDataPointer(new ElementType[v.size()], v.size(), false); } else if (this->dataSize != v.size()) { this->resize(v.size()); } ippsCopy(v.getDataPointer(), getDataPointer(), v.dataSize); return *this; } template inline VectorT& VectorT::operator=(const ElementType& element) { ippsSet(element, getDataPointer(), this->dataSize); return *this; } template void VectorT::flip() { ippsFlip_I(getDataPointer(), this->dataSize); } template void VectorT::sortAscend() { ippsSortAscend_I(getDataPointer(), this->dataSize); } template void VectorT::sortDescend() { ippsSortDescend_I(getDataPointer(), this->dataSize); } /** * @brief sort elements in an descending order. Permutation is only correct if all elements are different. */ template void VectorT::sortDescend(VectorT & permutation) { //copy elements to extract ordering information lateron VectorT tmp_cp(*this); // sort the elements ippsSortDescend_I(getDataPointer(), this->dataSize); //compute permutation permutation.resize(this->size()); int idxSelf ( 0 ); for (typename VectorT::const_iterator itSelf = (*this).begin(); itSelf != (*this).end(); itSelf++, idxSelf++) { int idxOrig ( 0 ); for (typename VectorT::const_iterator itOrig = tmp_cp.begin(); itOrig != tmp_cp.end(); itOrig++, idxOrig++) { if ( *itOrig == *itSelf ) { permutation[idxOrig] = idxSelf; break; } } } } template MatrixT VectorT::toCrossProductMatrix() const { MatrixT result(size(), size()); result(0, 0) = 0.0; result(0, 1) = -(*this)[2]; result(0, 2) = (*this)[1]; result(1, 0) = (*this)[2]; result(1, 1) = 0.0; result(1, 2) = -(*this)[0]; result(2, 0) = -(*this)[1]; result(2, 1) = (*this)[0]; result(2, 2) = 0.0; return result; } #define _DEFINE_EVECTOR_AUGMENTED_ASSIGNMENT(_Op, _Name) \ template \ inline VectorT & \ VectorT::operator _Op##= (const ElementType& v) { \ ipps##_Name##C_I(v, getDataPointer(), this->dataSize); \ return *this; \ } _DEFINE_EVECTOR_AUGMENTED_ASSIGNMENT(+, Add) _DEFINE_EVECTOR_AUGMENTED_ASSIGNMENT(-, Sub) _DEFINE_EVECTOR_AUGMENTED_ASSIGNMENT(*, Mul) _DEFINE_EVECTOR_AUGMENTED_ASSIGNMENT(/, Div) #define _DEFINE_EVECTOR_ASSIGNMENT(_Op, _Name) \ template \ inline VectorT & \ VectorT::operator _Op##= (const VectorT& v) { \ if(this->dataSize!=v.size()) \ _THROW_EVector("VectorT: different data size"); \ ipps##_Name##_I(v.getDataPointer(), getDataPointer(), this->dataSize); \ return *this; \ } _DEFINE_EVECTOR_ASSIGNMENT(+, Add) _DEFINE_EVECTOR_ASSIGNMENT(-, Sub) _DEFINE_EVECTOR_ASSIGNMENT(*, Mul) _DEFINE_EVECTOR_ASSIGNMENT(/, Div) // shift operations template VectorT VectorT::LShiftCircular(const uint b) { VectorT result(size()); Ipp32u bShift = b%size(); #ifdef NICE_USELIB_IPP ippsCopy(getDataPointer()+bShift, result.getDataPointer() , size()-bShift); ippsCopy(getDataPointer() , result.getDataPointer()+size()-bShift, bShift ); #else // NICE_USELIB_IPP memcpy(result.getDataPointer(), getDataPointer()+bShift, (size()-bShift)*sizeof(ElementType)); memcpy(result.getDataPointer()+size()-bShift, getDataPointer(), bShift*sizeof(ElementType)); #endif return result; } template void VectorT::LShiftCircularInplace(const uint b) { VectorT buffer = this->LShiftCircular(b); *this = buffer; } template VectorT VectorT::RShiftCircular(const uint b) { VectorT result(size()); Ipp32u bShift = b%size(); #ifdef NICE_USELIB_IPP ippsCopy(getDataPointer(), result.getDataPointer()+bShift, size()-bShift); ippsCopy(getDataPointer()+size()-bShift, result.getDataPointer(), bShift); #else // NICE_USELIB_IPP memcpy(result.getDataPointer()+bShift, getDataPointer(), (size()-bShift)*sizeof(ElementType)); memcpy(result.getDataPointer(), getDataPointer()+size()-bShift, bShift*sizeof(ElementType)); #endif return result; } template void VectorT::RShiftCircularInplace(const uint b) { VectorT buffer = this->RShiftCircular(b); *this = buffer; } template inline bool VectorT::isEqual(const VectorT &v, ElementType threshold) const { if( this->size() != v.size() ) _THROW_EVector("VectorT: different data size"); for (unsigned int j = 0; j < size(); j++) { if(fabs((*this)[j]-v[j])>threshold) return false; } return true; } template unsigned long VectorT::getHashValue() const { const char *buf = (const char*)getDataPointer(); uint len = size() * sizeof(ElementType); // might overflow...but we do not care about it // According to http://www.ntecs.de/projects/guugelhupf/doc/html/x435.html // this is what STL is using unsigned long hash = 0; for ( int i = 0 ; i < len ; i++ ) hash = 5*hash + buf[i]; return hash; } template std::vector VectorT::std_vector () const { std::vector dst ( this->size() ); for ( unsigned int i = 0 ; i < size(); i++ ) dst[i] = (*this)[i]; return dst; } } // namespace NICE #endif