/** * @file SparseVector.hpp * * SparseVector class. * * @author Kamil Ritz * @author Julian Kent * */ #pragma once #include "math.hpp" namespace matrix { template struct force_constexpr_eval { static const int value = N; }; // Vector that only store nonzero elements, // which indices are specified as parameter pack template class SparseVector { private: static constexpr size_t N = sizeof...(Idxs); static constexpr size_t _indices[N] {Idxs...}; static constexpr bool duplicateIndices() { for (size_t i = 0; i < N; i++) for (size_t j = 0; j < i; j++) if (_indices[i] == _indices[j]) return true; return false; } static constexpr size_t findMaxIndex() { size_t maxIndex = 0; for (size_t i = 0; i < N; i++) { if (maxIndex < _indices[i]) { maxIndex = _indices[i]; } } return maxIndex; } static_assert(duplicateIndices() == false, "Duplicate indices"); static_assert(N < M, "More entries than elements, use a dense vector"); static_assert(N > 0, "A sparse vector needs at least one element"); static_assert(findMaxIndex() < M, "Largest entry doesn't fit in sparse vector"); Type _data[N] {}; static constexpr int findCompressedIndex(size_t index) { int compressedIndex = -1; for (size_t i = 0; i < N; i++) { if (index == _indices[i]) { compressedIndex = static_cast(i); } } return compressedIndex; } public: constexpr size_t non_zeros() const { return N; } constexpr size_t index(size_t i) const { return SparseVector::_indices[i]; } SparseVector() = default; SparseVector(const matrix::Vector& data) { for (size_t i = 0; i < N; i++) { _data[i] = data(_indices[i]); } } explicit SparseVector(const Type data[N]) { memcpy(_data, data, sizeof(_data)); } template inline Type at() const { static constexpr int compressed_index = force_constexpr_eval::value; static_assert(compressed_index >= 0, "cannot access unpopulated indices"); return _data[compressed_index]; } template inline Type& at() { static constexpr int compressed_index = force_constexpr_eval::value; static_assert(compressed_index >= 0, "cannot access unpopulated indices"); return _data[compressed_index]; } inline Type atCompressedIndex(size_t i) const { assert(i < N); return _data[i]; } inline Type& atCompressedIndex(size_t i) { assert(i < N); return _data[i]; } void setZero() { for (size_t i = 0; i < N; i++) { _data[i] = Type(0); } } Type dot(const matrix::Vector& other) const { Type accum (0); for (size_t i = 0; i < N; i++) { accum += _data[i] * other(_indices[i]); } return accum; } matrix::Vector operator+(const matrix::Vector& other) const { matrix::Vector vec = other; for (size_t i = 0; i < N; i++) { vec(_indices[i]) += _data[i]; } return vec; } SparseVector& operator+=(Type t) { for (size_t i = 0; i < N; i++) { _data[i] += t; } return *this; } Type norm_squared() const { Type accum(0); for (size_t i = 0; i < N; i++) { accum += _data[i] * _data[i]; } return accum; } Type norm() const { return matrix::sqrt(norm_squared()); } bool longerThan(Type testVal) const { return norm_squared() > testVal*testVal; } }; template matrix::Vector operator*(const matrix::Matrix& mat, const matrix::SparseVector& vec) { matrix::Vector res; for (size_t i = 0; i < Q; i++) { const Vector row = mat.row(i); res(i) = vec.dot(row); } return res; } template constexpr size_t SparseVector::_indices[SparseVector::N]; template using SparseVectorf = SparseVector; }