#ifndef CLONEVECTOR_H #define CLONEVECTOR_H #include "Vector.h" 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* get_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 clown (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 { using std::min; 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 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); // NOTE: DO NOT do _baseX->set_elements_to() 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="); FORi VIDX(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="); FORi VIDX(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::get_ptr() const { if (_baseV) return _baseV->get_ptr(); #ifdef ROW_STORAGE if (_clone_type == CLONE_ROW) return _baseM->get_ptr() + this->size()*_idx; if (_clone_type == CLONE_COL) return _baseM->get_ptr() + this->size(); if (_clone_type == CLONE_DIAG) return _baseM->get_ptr(); #else if (_clone_type == CLONE_COL) return _baseM->get_ptr() + this->size()*_idx; if (_clone_type == CLONE_ROW) return _baseM->get_ptr() + this->size(); if (_clone_type == CLONE_DIAG) return _baseM->get_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(); 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->get_ptr(), ptr, this->size()*sizeof(T)); } #endif