#ifndef CLONEVECTOR_H #define CLONEVECTOR_H #include "Vector.h" #include namespace ATC_matrix { /** * @class CloneVector * @brief Class for creating objects that wrap matrix data for manipulation through vector operations */ template class CloneVector : public Vector { public: CloneVector(); // do not implement CloneVector(const Vector &c); CloneVector(const Matrix &c, int dim, INDEX idx=0); CloneVector(const DiagonalMatrix &c, INDEX idx=0); // overloaded virtual functions T& operator[](INDEX i); T operator[](INDEX i) const; T operator()(INDEX i, INDEX j=0) const; T& operator()(INDEX i, INDEX j=0); INDEX nRows() const; CloneVector& operator=(const T &v); CloneVector& operator=(const CloneVector &C); CloneVector& operator=(const Matrix &C); virtual bool memory_contiguous() const; T* ptr() const; void resize(INDEX nRows, INDEX nCols=0, bool copy=false); void reset(INDEX nRows, INDEX nCols=0, bool zero=true); void copy(const T * ptr, INDEX nRows, INDEX nCols=0); private: void _resize(INDEX nRows, INDEX nCols, bool copy, bool zero); Vector * const _baseV; // ptr to a base vector Matrix * const _baseM; // ptr to a base matrix int _clone_type; // what to clone (see enum CLONE_TYPE) INDEX _idx; // index of matrix dimension to clone }; /////////////////////////////////////////////////////////////////////////////// // Template definitions /////////////////////////////////////////////////////// //----------------------------------------------------------------------------- // Construct from another vector //----------------------------------------------------------------------------- template CloneVector::CloneVector(const Vector &c) : Vector(), _baseV(const_cast*>(&c)), _baseM(NULL) {} //----------------------------------------------------------------------------- // Construct from a matrix, the const_cast isn't pretty /* CloneVector(const Matrix &c, int dim, INDEX idx) / attaches to a slice of a matrix / Arguments: c = pointer to the matrix / dim = type of slice CLONE_ROW, CLONE_COL, CLONE_DIAG / idx = index of row or column (no effect on diag currently) */ //----------------------------------------------------------------------------- template CloneVector::CloneVector(const Matrix &c, int dim, INDEX idx) : Vector(), _baseV(NULL), _baseM(const_cast*>(&c)) , _clone_type(dim), _idx(idx) {} //----------------------------------------------------------------------------- // Construct from a DiagonalMatrix //----------------------------------------------------------------------------- template CloneVector::CloneVector(const DiagonalMatrix &c, INDEX idx) : Vector(), _baseV(NULL), _baseM(const_cast*>(&c)) , _clone_type(CLONE_DIAG), _idx(0) {} //----------------------------------------------------------------------------- // value (const) indexing operator //----------------------------------------------------------------------------- template T CloneVector::operator()(INDEX i, INDEX j) const { return (*this)[i]; } //----------------------------------------------------------------------------- // reference index operator //----------------------------------------------------------------------------- template T& CloneVector::operator()(INDEX i, INDEX j) { return (*this)[i]; } //----------------------------------------------------------------------------- // Indexes the cloned vector either from another vector or a matrix //----------------------------------------------------------------------------- template T CloneVector::operator[](INDEX i) const { if (_baseV) return (*_baseV)(i); if (_clone_type == CLONE_ROW) return (*_baseM)(_idx, i); else if (_clone_type == CLONE_COL) return (*_baseM)(i,_idx); else if (_clone_type == CLONE_DIAG) return (*_baseM)(i,i); return 0; } //----------------------------------------------------------------------------- // Indexes the cloned vector either from another vector or a matrix //----------------------------------------------------------------------------- template T& CloneVector::operator[](INDEX i) { if (_baseV) return (*_baseV)(i); if (_clone_type == CLONE_ROW) return (*_baseM)(_idx, i); if (_clone_type == CLONE_COL) return (*_baseM)(i,_idx); if (_clone_type == CLONE_DIAG) return (*_baseM)(i,i); return (*_baseV)(i); } //----------------------------------------------------------------------------- // Returns the size of the base vector or of the row/col of the base matrix //----------------------------------------------------------------------------- template INDEX CloneVector::nRows() const { if (_baseV) return _baseV->size(); if (_clone_type == CLONE_ROW) return _baseM->nCols(); if (_clone_type == CLONE_COL) return _baseM->nRows(); if (_clone_type == CLONE_DIAG) return std::min(_baseM->nRows(), _baseM->nCols()); return 0; } //----------------------------------------------------------------------------- // assigns all elements to a constant //----------------------------------------------------------------------------- template CloneVector& CloneVector::operator=(const T &v) { this->set_all_elements_to(v); return *this; } //----------------------------------------------------------------------------- // assigns all elements to the corresponding elements in C //----------------------------------------------------------------------------- template CloneVector& CloneVector::operator=(const CloneVector &C) { GCK(*this, C, this->size()!=C.size(), "Error in CloneVector:operator="); int sz = this->size(); for (INDEX i = 0; i < sz; i++) (*this)[i] = C[i]; return *this; } //----------------------------------------------------------------------------- // assigns all elements to the corresponding elements in C //----------------------------------------------------------------------------- template CloneVector& CloneVector::operator=(const Matrix &C) { GCK(*this, C, this->size()!=C.size(), "Error in CloneVector:operator="); int sz = this->size(); for (INDEX i = 0; i < sz; i++) (*this)[i] = C[i]; return *this; } //----------------------------------------------------------------------------- // returns true only if its guaranteed memory is contiguous //----------------------------------------------------------------------------- template bool CloneVector::memory_contiguous() const { // drill down through clone of clones if (_baseV) return _baseV->memory_contiguous(); // could be okay if DiagonalMatrix, but can't guarantee this if (_clone_type == CLONE_DIAG) return false; #ifdef ROW_STORAGE return _clone_type == CLONE_ROW; #else return _clone_type == CLONE_COL; #endif } //----------------------------------------------------------------------------- // Returns a pointer to the data unless the data is a column of a matrix //----------------------------------------------------------------------------- template T* CloneVector::ptr() const { if (_baseV) return _baseV->ptr(); #ifdef ROW_STORAGE if (_clone_type == CLONE_ROW) return _baseM->ptr() + this->size()*_idx; if (_clone_type == CLONE_COL) return _baseM->ptr() + this->size(); if (_clone_type == CLONE_DIAG) return _baseM->ptr(); #else if (_clone_type == CLONE_COL) return _baseM->ptr() + this->size()*_idx; if (_clone_type == CLONE_ROW) return _baseM->ptr() + this->size(); if (_clone_type == CLONE_DIAG) return _baseM->ptr(); #endif return 0; } //----------------------------------------------------------------------------- // general resize function, can handle parents that are matrices or vectors //----------------------------------------------------------------------------- template void CloneVector::_resize(INDEX nRows, INDEX nCols, bool copy, bool zero) { if (_baseV) { if (copy) _baseV->resize(nRows, nCols, copy); else _baseV->reset (nRows, nCols, zero); return; } // parent is a matrix, need to decide what the Vector is cloning switch (_clone_type) { case CLONE_ROW: // now the leading dimension is rows nCols = nCols ? nCols : _baseM->nCols(); break; case CLONE_COL: // now the leading dimension is columns nCols = nCols ? nCols : _baseM->nRows(); ATC_Utility::swap(nRows, nCols); break; case CLONE_DIAG: // lets just hope you knew what you were doing break; default: return; } if (zero) _baseM->reset(nRows, nCols, zero); // zero overrides copy else _baseM->resize(nRows, nCols, copy); } //----------------------------------------------------------------------------- // resizes the matrix and optionally copies what fits //----------------------------------------------------------------------------- template void CloneVector::resize(INDEX nRows, INDEX nCols, bool copy) { _resize(nRows, nCols, copy, false); } //----------------------------------------------------------------------------- // resizes the matrix and optionally zeros it out //----------------------------------------------------------------------------- template void CloneVector::reset(INDEX nRows, INDEX nCols, bool zero) { _resize(nRows, nCols, false, zero); } //----------------------------------------------------------------------------- // resizes the matrix and copies data //----------------------------------------------------------------------------- template void CloneVector::copy(const T * ptr, INDEX nRows, INDEX nCols) { _resize(nRows, nCols, false, false); memcpy(this->ptr(), ptr, this->size()*sizeof(T)); } } // end namespace #endif