|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- /**
- * \file impl.hpp
- * \brief Implementation common header file
- *
- * \author
- * Christos Choutouridis AEM:8997
- * <cchoutou@ece.auth.gr>
- */
- #ifndef IMPL_HPP_
- #define IMPL_HPP_
-
- #include <type_traits>
- #include <utility>
- #include <algorithm>
- #include <vector>
- #include <tuple>
- #include <cstddef>
- #include <iostream>
- #include <fstream>
-
- using std::size_t;
-
- /*
- * Small helper to strip types
- */
- template<typename T>
- struct remove_cvref {
- typedef std::remove_cv_t<std::remove_reference_t<T>> type;
- };
- template<typename T>
- using remove_cvref_t = typename remove_cvref<T>::type;
-
- /*!
- * Enumerator to denote the storage type of the array to use.
- */
- enum class MatrixType {
- FULL, /*!< Matrix is asymmetric */
- SYMMETRIC, /*!< Matrix is symmetric */
- };
-
- /*
- * Forward type declerations
- */
- template<typename DataType, typename IndexType, MatrixType Type = MatrixType::SYMMETRIC> struct Matrix;
- template<typename DataType, typename IndexType, MatrixType Type = MatrixType::SYMMETRIC> struct SpMat;
- template<typename DataType, typename IndexType> struct SpMatCol;
- template<typename DataType, typename IndexType> struct SpMatRow;
- template<typename DataType, typename IndexType> struct SpMatVal;
-
- /*!
- * 2D-array wrapper for v1 and v2 part of the exercise t use as RAII
- * and copy-prevention.
- *
- * This is a very thin abstraction layer over a native array.
- * This is tested using compiler explorer and our template produce
- * almost identical assembly.
- *
- * The penalty hit we have is due to the fact that we use a one dimension array
- * and we have to calculate the actual position from an (i,j) pair.
- * The use of 1D array was our intention from the beginning, so the penalty
- * was pretty much unavoidable.
- *
- * \tparam DataType The underling data type of the array
- * \tparam Type The storage type of the array
- * \arg FULL For full matrix
- * \arg SYMMETRIC For symmetric matrix (we use only the lower part)
- */
- template<typename DataType, typename IndexType, MatrixType Type>
- struct Matrix {
-
- using dataType = DataType; //!< meta:export of underling data type
- using indexType = IndexType; //!< meta:export of underling index type
- static constexpr MatrixType matrixType = Type; //!< export of array type
-
- /*!
- * \name Obj lifetime
- */
- //! @{
-
- //! Constructor using data type and size
- Matrix(DataType* t, IndexType s) noexcept : m_(t), size_(s) { }
-
- //! RAII deleter
- ~Matrix() { delete m_; }
- //! move ctor
- Matrix(Matrix&& a) noexcept { a.swap(*this); }
- //! move
- Matrix& operator=(Matrix&& a) noexcept { a.swap(*this); return *this; }
- Matrix(const Matrix& a) = delete; //!< No copy ctor
- Matrix& operator=(const Matrix& a) = delete; //!< No copy
- //! @}
-
- //! \name Data exposure
- //! @{
-
- //! memory capacity of the matrix with diagonal data
- template<MatrixType AT=Type> std::enable_if_t<AT==MatrixType::SYMMETRIC, IndexType>
- static constexpr capacity(IndexType N) noexcept { return (N+1)*N/2; }
- //! memory capacity for full matrix
- template<MatrixType AT=Type> std::enable_if_t<AT==MatrixType::FULL, IndexType>
- static constexpr capacity(IndexType N) noexcept { return N*N; }
-
- //! Get the size of each dimension
- IndexType size() noexcept { return size_; }
-
- /*
- * virtual 2D accessors
- */
- template<MatrixType AT=Type>
- std::enable_if_t <AT==MatrixType::SYMMETRIC, DataType>
- get (IndexType i, IndexType j) {
- if (i<j) return m_[j*(j+1)/2 + i]; // Upper, use opposite index
- else return m_[i*(i+1)/2 + j]; // Lower, use our notation
- }
- template<MatrixType AT=Type>
- std::enable_if_t <AT==MatrixType::FULL, DataType>
- get(IndexType i, IndexType j) {
- return m_[i*size_ + j];
- }
- template<MatrixType AT=Type>
- std::enable_if_t <AT==MatrixType::SYMMETRIC, DataType>
- set(DataType v, IndexType i, IndexType j) {
- if (i<j) return m_[j*(j+1)/2 + i] =v; // Upper, use opposite index
- else return m_[i*(i+1)/2 + j] =v; // Lower, use our notation
- }
- template<MatrixType AT=Type>
- std::enable_if_t <AT==MatrixType::FULL, DataType>
- set(DataType v, IndexType i, IndexType j) {
- return m_[i*size_ + j] =v;
- }
- DataType operator()(IndexType i, IndexType j) { return get(i, j); }
-
- // a basic serial iterator support
- DataType* begin() noexcept { return m_; }
- DataType* end() noexcept { return m_ + Matrix::capacity(size_); }
- //! @}
-
- /*!
- * \name Safe iteration API
- *
- * This api automates the iteration over the array based on
- * MatrixType
- */
- //! @{
- template<typename F, typename... Args>
- void for_each_in (IndexType begin, IndexType end, F&& lambda, Args&&... args) {
- for (IndexType it=begin ; it<end ; ++it) {
- std::forward<F>(lambda)(std::forward<Args>(args)..., it);
- }
- }
- //! @}
-
- // move helper
- void swap(Matrix& src) noexcept {
- std::swap(m_, src.m_);
- std::swap(size_, src.size_);
- }
- private:
- DataType* m_; //!< Pointer to actual data.
- IndexType size_; //!< the virtual size of each dimension.
- };
-
- /*!
- * RAII allocation helper, the smart_ptr way.
- */
- template<typename DataType, typename IndexType, MatrixType Type = MatrixType::SYMMETRIC>
- Matrix<DataType, IndexType, Type> make_Matrix(IndexType s) {
- return Matrix<DataType, IndexType, Type>(new DataType[Matrix<DataType, IndexType, Type>::capacity(s)], s);
- }
-
- template<typename DataType, typename IndexType>
- using CooVal = std::tuple<DataType, IndexType, IndexType>;
-
- template<typename DataType, typename IndexType, MatrixType Type>
- struct SpMat {
- using dataType = DataType; //!< meta:export of underling data type
- using indexType = IndexType; //!< meta:export of underling index type
- static constexpr MatrixType matrixType = Type; //!< export of array type
-
- friend class SpMatCol<DataType, IndexType>;
- friend class SpMatRow<DataType, IndexType>;
- friend class SpMatVal<DataType, IndexType>;
-
- /*!
- * \name Obj lifetime
- */
- //! @{
-
- //! allocation with init value ctor
- SpMat(IndexType n=IndexType{}, IndexType nnz=IndexType{}) :
- values(nnz, DataType{}),
- rows(nnz, IndexType{}),
- col_ptr((n)? n+1:2, IndexType{}),
- N(n),
- NNZ(nnz) { }
-
- SpMat(IndexType n, IndexType nnz, const IndexType* row, const IndexType* col) :
- values(nnz, 1),
- rows(row, row+nnz),
- col_ptr(col, col+n+1),
- N(n),
- NNZ(nnz) { }
-
- SpMat(IndexType n, IndexType nnz, const DataType* v, const IndexType* row, const IndexType* col) :
- values(v, v+nnz),
- rows(row, row+nnz),
- col_ptr(col, col+n+1),
- N(n),
- NNZ(nnz) { }
-
- SpMat(IndexType n, IndexType nnz, const DataType v, const std::vector<IndexType>& row, const std::vector<IndexType>& col) :
- values(nnz, v),
- rows (row),
- col_ptr(col),
- N(n),
- NNZ(nnz) { }
-
- //! move ctor
- SpMat(SpMat&& a) noexcept { moves(std::move(a)); }
- //! move
- SpMat& operator=(SpMat&& a) noexcept { moves(std::move(a)); return *this; }
- SpMat(const SpMat& a) = delete; //!< No copy ctor
- SpMat& operator=(const SpMat& a) = delete; //!< No copy assignment
- //! @}
-
- //! \name Data exposure
- //! @{
- IndexType size() noexcept { return N; }
- IndexType size(IndexType n) {
- col_ptr.resize(n+1);
- return N = n;
- }
- IndexType capacity() noexcept { return NNZ; }
- IndexType capacity(IndexType nnz) {
- values.reserve(nnz);
- rows.reserve(nnz);
- return NNZ;
- }
- std::vector<IndexType>& getRows() noexcept { return rows; }
- std::vector<IndexType>& getCols() noexcept { return col_ptr; }
-
- SpMatVal<DataType, IndexType> operator()(IndexType i, IndexType j) {
- return SpMatVal<DataType, IndexType>(this, get(i, j), i, j);
- }
- DataType get(IndexType i, IndexType j) {
- IndexType idx;
- bool found;
- std::tie(idx, found) =find_idx(rows, col_ptr[j], col_ptr[j+1], i);
- return (found) ? values[idx] : 0;
- }
- DataType set(DataType v, IndexType i, IndexType j) {
- IndexType idx; bool found;
- std::tie(idx, found) = find_idx(rows, col_ptr[j], col_ptr[j+1], i);
- if (found)
- return values[idx] = v; // we don't change NNZ even if we write "0"
- else {
- values.insert(values.begin()+idx, v);
- rows.insert(rows.begin()+idx, i);
- std::transform(col_ptr.begin()+j+1, col_ptr.end(), col_ptr.begin()+j+1, [](IndexType it) {
- return ++it;
- });
- ++NNZ; // we increase the NNZ even if we write "0"
- return v;
- }
- }
-
-
- SpMatCol<DataType, IndexType> getCol(IndexType j) {
- return SpMatCol<DataType, IndexType>(this, col_ptr[j], col_ptr[j+1]);
- }
- template<MatrixType AT= Type>
- std::enable_if_t<AT==MatrixType::SYMMETRIC, SpMatCol<DataType, IndexType>>
- getRow(IndexType i) {
- return getCol(i);
- }
- template<MatrixType AT= Type>
- std::enable_if_t<AT==MatrixType::FULL, SpMatCol<DataType, IndexType>>
- getRow(IndexType i) {
- return SpMatRow<DataType, IndexType>(this, i);
- }
-
- // iterator support
- DataType* begin() noexcept { return values.begin(); }
- DataType* end() noexcept { return values.end(); }
- //! @}
-
- /*!
- * \name Safe iteration API
- *
- * This api automates the iteration over the array based on
- * MatrixType
- */
- //! @{
-
- template<typename F, typename... Args>
- void for_each_in (IndexType begin, IndexType end, F&& lambda, Args&&... args) {
- for (IndexType it=begin ; it<end ; ++it) {
- std::forward<F>(lambda)(std::forward<Args>(args)..., it);
- }
- }
-
- //! @}
-
- // operations
- template<typename D, typename I, MatrixType T> friend void print(SpMat<D, I, T>& mat);
- template<typename D, typename I, MatrixType T> friend void print_dense(SpMat<D, I, T>& mat);
-
- private:
- // index-find helper
- std::pair<IndexType, bool> find_idx(const std::vector<IndexType>& v, IndexType begin, IndexType end, IndexType match) {
- for ( ; begin < end ; ++begin) {
- if (match == v[begin]) return std::make_pair(begin, true);
- else if (match < v[begin]) return std::make_pair(begin, false);
- }
- return std::make_pair(end, false);
- }
- // move helper
- void moves(SpMat&& src) noexcept {
- values = std::move(src.values);
- rows = std::move(src.rows);
- col_ptr = std::move(src.col_ptr);
- N = std::move(src.N); // redundant for primitives
- NNZ = std::move(src.NNZ); //
- }
- //! \name Data
- //! @{
- std::vector<DataType> values {};
- std::vector<IndexType> rows{};
- std::vector<IndexType> col_ptr{1,0};
- IndexType N{0};
- IndexType NNZ{0};
- //! @}
- };
-
- template<typename DataType, typename IndexType>
- struct SpMatCol {
- using owner_t = SpMat<DataType, IndexType>;
-
- SpMatCol(owner_t* own, const IndexType begin, const IndexType end) noexcept :
- owner_(own), index_(begin), begin_(begin), end_(end) {
- vindex_ = vIndexCalc(index_);
- }
- SpMatCol() = default;
- SpMatCol(const SpMatCol&) = delete;
- SpMatCol& operator=(const SpMatCol&)= delete;
- SpMatCol(SpMatCol&&) = default;
- SpMatCol& operator=(SpMatCol&&) = default;
-
- DataType operator* () {
- return get();
- }
- SpMatCol& operator++ () { advance(); return *this; }
- SpMatCol& operator++ (int) { SpMatCol& p = *this; advance(); return p; }
-
- DataType operator()(IndexType x) {
- return (x == index())? get() : DataType{};
- }
- DataType operator= (DataType v) { return owner_->values[index_] = v; }
- IndexType index() noexcept { return vindex_; }
- const IndexType index() const noexcept { return vindex_; }
- IndexType begin() noexcept { return vIndexCalc(begin_); }
- const IndexType begin() const noexcept { return vIndexCalc(begin_); }
- IndexType end() noexcept { return owner_->N; }
- const IndexType end() const noexcept { return owner_->N; }
-
- template <typename C>
- DataType operator* (C&& c) {
- static_assert(std::is_same<remove_cvref_t<C>, SpMatCol<DataType, IndexType>>(), "");
- DataType v{};
- while (index() != end() && c.index() != c.end()) {
- if (index() < c.index()) advance();
- else if (index() > c.index()) ++c;
- else { //index() == c.index()
- v += get() * *c;
- ++c;
- advance();
- }
- }
- return v;
- }
-
- private:
- void advance() noexcept {
- ++index_;
- vindex_ = vIndexCalc(index_);
- }
- IndexType vIndexCalc(IndexType idx) {
- return (idx < end_) ? owner_->rows[idx] : end();
- }
- DataType get() { return owner_->values[index_]; }
- owner_t* owner_{nullptr};
- IndexType vindex_ {IndexType{}};
- IndexType index_{IndexType{}};
- IndexType begin_{IndexType{}};
- IndexType end_{IndexType{}};
- };
-
- template<typename DataType, typename IndexType>
- struct SpMatRow {
- using owner_t = SpMat<DataType, IndexType>;
-
- SpMatRow(owner_t* own, const IndexType row) noexcept :
- owner_(own), vindex_(IndexType{}), row_(row), index_(IndexType{}),
- begin_(IndexType{}), end_(owner_->NNZ) {
- // place begin
- while(begin_ != end_ && owner_->rows[begin_] != row_)
- ++begin_;
- // place index_ and vindex_
- if (owner_->rows[index_] != row_)
- advance();
- }
- SpMatRow() = default;
- SpMatRow(const SpMatRow&) = delete;
- SpMatRow& operator=(const SpMatRow&)= delete;
- SpMatRow(SpMatRow&&) = default;
- SpMatRow& operator=(SpMatRow&&) = default;
-
- DataType operator* () {
- return get();
- }
- SpMatRow& operator++ () { advance(); return *this; }
- SpMatRow& operator++ (int) { SpMatRow& p = *this; advance(); return p; }
- DataType operator()(IndexType x) {
- return (x == index())? get() : DataType{};
- }
- DataType operator= (DataType v) { return owner_->values[index_] = v; }
- IndexType index() noexcept { return vindex_; }
- const IndexType index() const noexcept { return vindex_; }
- IndexType begin() noexcept { return vIndexCalc(begin_); }
- const IndexType begin() const noexcept { return vIndexCalc(begin_); }
- IndexType end() noexcept { return owner_->N; }
- const IndexType end() const noexcept { return owner_->N; }
-
- template <typename C>
- DataType operator* (C&& c) {
- static_assert(std::is_same<remove_cvref_t<C>, SpMatCol<DataType, IndexType>>(), "");
- DataType v{};
- while (index() != end() && c.index() != c.end()) {
- if (index() < c.index()) advance();
- else if (index() > c.index()) ++c;
- else { //index() == c.index()
- v += get()* *c;
- ++c;
- advance();
- }
- }
- return v;
- }
- private:
- void advance() noexcept {
- do
- ++index_;
- while(index_ != end_ && owner_->rows[index_] != row_);
- vindex_ = vIndexCalc(index_);
- }
- IndexType vIndexCalc(IndexType idx) {
- for(IndexType i =0 ; i<(owner_->N+1) ; ++i)
- if (idx < owner_->col_ptr[i])
- return i-1;
- return end();
- }
- DataType get() { return owner_->values[index_]; }
- owner_t* owner_ {nullptr};
- IndexType vindex_ {IndexType{}};
- IndexType row_ {IndexType{}};
- IndexType index_ {IndexType{}};
- IndexType begin_ {IndexType{}};
- IndexType end_ {IndexType{}};
- };
-
- template<typename DataType, typename IndexType>
- struct SpMatVal {
- using owner_t = SpMat<DataType, IndexType>;
-
- SpMatVal(owner_t* own, DataType v, IndexType i, IndexType j) :
- owner_(own), v_(v), i_(i), j_(j) { }
- SpMatVal() = default;
- SpMatVal(const SpMatVal&) = delete;
- SpMatVal& operator=(const SpMatVal&) = delete;
- SpMatVal(SpMatVal&&) = default;
- SpMatVal& operator=(SpMatVal&&) = default;
-
- operator DataType() { return v_; }
- SpMatVal& operator=(DataType v) {
- v_ = v;
- owner_->set(v_, i_, j_);
- return *this;
- }
- private:
- owner_t* owner_{nullptr};;
- DataType v_{DataType{}};
- IndexType i_{IndexType{}};
- IndexType j_{IndexType{}};
- };
-
-
- enum class InputMatrix{
- GENERATE,
- MTX
- };
-
- /*!
- * Session option for each invocation of the executable
- */
- struct session_t {
- std::size_t size {0};
- double probability {0};
- InputMatrix inputMatrix {InputMatrix::GENERATE};
- std::ifstream mtxFile {};
- std::size_t print_size {80};
- bool timing {false};
- bool print {false};
- bool makeSymmetric {false};
- };
-
- extern session_t session;
-
-
- #endif /* IMPL_HPP_ */
|