// This file is part of Eigen, a lightweight C++ template library // for linear algebra. Eigen itself is part of the KDE project. // // Copyright (C) 2008 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_SPARSEVECTOR_H #define EIGEN_SPARSEVECTOR_H /** \class SparseVector * * \brief a sparse vector class * * \param _Scalar the scalar type, i.e. the type of the coefficients * * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * */ template struct ei_traits > { typedef _Scalar Scalar; enum { IsColVector = _Flags & RowMajorBit ? 0 : 1, RowsAtCompileTime = IsColVector ? Dynamic : 1, ColsAtCompileTime = IsColVector ? 1 : Dynamic, MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, Flags = SparseBit | _Flags, CoeffReadCost = NumTraits::ReadCost, SupportedAccessPatterns = FullyCoherentAccessPattern }; }; template class SparseVector : public SparseMatrixBase > { public: EIGEN_GENERIC_PUBLIC_INTERFACE(SparseVector) protected: public: typedef SparseMatrixBase SparseBase; enum { IsColVector = ei_traits::IsColVector }; SparseArray m_data; int m_size; public: inline int rows() const { return IsColVector ? m_size : 1; } inline int cols() const { return IsColVector ? 1 : m_size; } inline int innerSize() const { return m_size; } inline int outerSize() const { return 1; } inline int innerNonZeros(int j) const { ei_assert(j==0); return m_size; } inline const Scalar* _valuePtr() const { return &m_data.value(0); } inline Scalar* _valuePtr() { return &m_data.value(0); } inline const int* _innerIndexPtr() const { return &m_data.index(0); } inline int* _innerIndexPtr() { return &m_data.index(0); } inline Scalar coeff(int row, int col) const { ei_assert((IsColVector ? col : row)==0); return coeff(IsColVector ? row : col); } inline Scalar coeff(int i) const { int start = 0; int end = m_data.size(); if (start==end) return Scalar(0); else if (end>0 && i==m_data.index(end-1)) return m_data.value(end-1); // ^^ optimization: let's first check if it is the last coefficient // (very common in high level algorithms) // TODO move this search to ScalarArray const int* r = std::lower_bound(&m_data.index(start),&m_data.index(end-1),i); const int id = r-&m_data.index(0); return ((*r==i) && (id=start && "you probably called coeffRef on a non finalized vector"); ei_assert(end>start && "coeffRef cannot be called on a zero coefficient"); int* r = std::lower_bound(&m_data.index(start),&m_data.index(end),i); const int id = r-&m_data.index(0); ei_assert((*r==i) && (id= startId) && (m_data.index(id) > i) ) { m_data.index(id+1) = m_data.index(id); m_data.value(id+1) = m_data.value(id); --id; } m_data.index(id+1) = i; m_data.value(id+1) = 0; return m_data.value(id+1); } void resize(int newSize) { m_size = newSize; m_data.clear(); } void resizeNonZeros(int size) { m_data.resize(size); } inline SparseVector() : m_size(0) { resize(0, 0); } inline SparseVector(int size) : m_size(0) { resize(size); } template inline SparseVector(const MatrixBase& other) : m_size(0) { *this = other.derived(); } inline SparseVector(const SparseVector& other) : m_size(0) { *this = other.derived(); } inline void swap(SparseVector& other) { std::swap(m_size, other.m_size); m_data.swap(other.m_data); } inline SparseVector& operator=(const SparseVector& other) { if (other.isRValue()) { swap(other.const_cast_derived()); } else { resize(other.size()); m_data = other.m_data; } return *this; } // template // inline SparseVector& operator=(const MatrixBase& other) // { // const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); // if (needToTranspose) // { // // two passes algorithm: // // 1 - compute the number of coeffs per dest inner vector // // 2 - do the actual copy/eval // // Since each coeff of the rhs has to be evaluated twice, let's evauluate it if needed // typedef typename ei_nested::type OtherCopy; // OtherCopy otherCopy(other.derived()); // typedef typename ei_cleantype::type _OtherCopy; // // resize(other.rows(), other.cols()); // Eigen::Map(m_outerIndex,outerSize()).setZero(); // // pass 1 // // FIXME the above copy could be merged with that pass // for (int j=0; j::operator=(other.derived()); // } // } friend std::ostream & operator << (std::ostream & s, const SparseVector& m) { for (unsigned int i=0; i class SparseVector::InnerIterator { public: InnerIterator(const SparseVector& vec, int outer=0) : m_vector(vec), m_id(0), m_end(vec.nonZeros()) { ei_assert(outer==0); } template InnerIterator(const Flagged& vec, int outer) : m_vector(vec._expression()), m_id(0), m_end(m_vector.nonZeros()) {} inline InnerIterator& operator++() { m_id++; return *this; } inline Scalar value() const { return m_vector.m_data.value(m_id); } inline int index() const { return m_vector.m_data.index(m_id); } inline operator bool() const { return (m_id < m_end); } protected: const SparseVector& m_vector; int m_id; const int m_end; }; #endif // EIGEN_SPARSEVECTOR_H