A triangle counting assignment for A.U.TH Parallel and distributed systems class.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

739 lines
28 KiB

  1. /**
  2. * \file impl.hpp
  3. * \brief Implementation common header file
  4. *
  5. * \author
  6. * Christos Choutouridis AEM:8997
  7. * <cchoutou@ece.auth.gr>
  8. */
  9. #ifndef IMPL_HPP_
  10. #define IMPL_HPP_
  11. #include <type_traits>
  12. #include <utility>
  13. #include <algorithm>
  14. #include <vector>
  15. #include <tuple>
  16. #include <cstddef>
  17. #include <iostream>
  18. #include <fstream>
  19. using std::size_t;
  20. /*
  21. * Small helper to strip types
  22. */
  23. template<typename T>
  24. struct remove_cvref {
  25. typedef std::remove_cv_t<std::remove_reference_t<T>> type;
  26. };
  27. template<typename T>
  28. using remove_cvref_t = typename remove_cvref<T>::type;
  29. /*!
  30. * Enumerator to denote the storage type of the array to use.
  31. */
  32. enum class MatrixType {
  33. FULL, /*!< Matrix is asymmetric */
  34. SYMMETRIC, /*!< Matrix is symmetric */
  35. };
  36. /*
  37. * Forward type declarations
  38. */
  39. template<typename DataType, typename IndexType, MatrixType Type = MatrixType::SYMMETRIC> struct Matrix;
  40. template<typename DataType, typename IndexType, MatrixType Type = MatrixType::SYMMETRIC> struct SpMat;
  41. template<typename DataType, typename IndexType> struct SpMatCol;
  42. template<typename DataType, typename IndexType> struct SpMatRow;
  43. template<typename DataType, typename IndexType> struct SpMatVal;
  44. /*!
  45. * 2D-array wrapper for v1 and v2 part of the exercise used as RAII
  46. * and copy-prevention.
  47. *
  48. * This is a very thin abstraction layer over a native array.
  49. * This is tested using compiler explorer and our template produce
  50. * almost identical assembly.
  51. *
  52. * The penalty hit we have is due to the fact that we use a one dimension array
  53. * and we have to calculate the actual position from an (i,j) pair.
  54. * The use of 1D array was our intention from the beginning, so the penalty
  55. * was pretty much unavoidable.
  56. *
  57. * \tparam DataType The underling data type of the array
  58. * \tparam Type The storage type of the array
  59. * \arg FULL For full matrix
  60. * \arg SYMMETRIC For symmetric matrix (we use only the lower part)
  61. */
  62. template<typename DataType, typename IndexType, MatrixType Type>
  63. struct Matrix {
  64. using dataType = DataType; //!< meta:export of underling data type
  65. using indexType = IndexType; //!< meta:export of underling index type
  66. static constexpr MatrixType matrixType = Type; //!< export of array type
  67. /*!
  68. * \name Obj lifetime
  69. */
  70. //! @{
  71. //! Constructor using data type and size
  72. Matrix(DataType* t, IndexType s) noexcept : m_(t), size_(s) { }
  73. //! RAII deleter
  74. ~Matrix() { delete m_; }
  75. //! move ctor
  76. Matrix(Matrix&& a) noexcept { a.swap(*this); }
  77. //! move
  78. Matrix& operator=(Matrix&& a) noexcept { a.swap(*this); return *this; }
  79. Matrix(const Matrix& a) = delete; //!< No copy ctor
  80. Matrix& operator=(const Matrix& a) = delete; //!< No copy
  81. //! @}
  82. //! \name Data exposure
  83. //! @{
  84. //! memory capacity of the matrix with diagonal data
  85. template<MatrixType AT=Type> std::enable_if_t<AT==MatrixType::SYMMETRIC, IndexType>
  86. static constexpr capacity(IndexType N) noexcept { return (N+1)*N/2; }
  87. //! memory capacity for full matrix
  88. template<MatrixType AT=Type> std::enable_if_t<AT==MatrixType::FULL, IndexType>
  89. static constexpr capacity(IndexType N) noexcept { return N*N; }
  90. //! Get the size of each dimension
  91. IndexType size() noexcept { return size_; }
  92. /*
  93. * virtual 2D accessors
  94. */
  95. template<MatrixType AT=Type>
  96. std::enable_if_t <AT==MatrixType::SYMMETRIC, DataType>
  97. get (IndexType i, IndexType j) {
  98. if (i<j) return m_[j*(j+1)/2 + i]; // Upper, use opposite index
  99. else return m_[i*(i+1)/2 + j]; // Lower, use our notation
  100. }
  101. template<MatrixType AT=Type>
  102. std::enable_if_t <AT==MatrixType::FULL, DataType>
  103. get(IndexType i, IndexType j) {
  104. return m_[i*size_ + j];
  105. }
  106. template<MatrixType AT=Type>
  107. std::enable_if_t <AT==MatrixType::SYMMETRIC, DataType>
  108. set(DataType v, IndexType i, IndexType j) {
  109. if (i<j) return m_[j*(j+1)/2 + i] =v; // Upper, use opposite index
  110. else return m_[i*(i+1)/2 + j] =v; // Lower, use our notation
  111. }
  112. template<MatrixType AT=Type>
  113. std::enable_if_t <AT==MatrixType::FULL, DataType>
  114. set(DataType v, IndexType i, IndexType j) {
  115. return m_[i*size_ + j] =v;
  116. }
  117. DataType operator()(IndexType i, IndexType j) { return get(i, j); }
  118. // a basic serial iterator support
  119. DataType* begin() noexcept { return m_; }
  120. DataType* end() noexcept { return m_ + Matrix::capacity(size_); }
  121. //! @}
  122. /*!
  123. * \name Safe iteration API
  124. *
  125. * This api automates the iteration over the array based on
  126. * MatrixType
  127. */
  128. //! @{
  129. template<typename F, typename... Args>
  130. void for_each_in (IndexType begin, IndexType end, F&& lambda, Args&&... args) {
  131. for (IndexType it=begin ; it<end ; ++it) {
  132. std::forward<F>(lambda)(std::forward<Args>(args)..., it);
  133. }
  134. }
  135. //! @}
  136. // move helper
  137. void swap(Matrix& src) noexcept {
  138. std::swap(m_, src.m_);
  139. std::swap(size_, src.size_);
  140. }
  141. private:
  142. DataType* m_; //!< Pointer to actual data.
  143. IndexType size_; //!< the virtual size of each dimension.
  144. };
  145. /*!
  146. * RAII allocation helper, the smart_ptr way.
  147. */
  148. template<typename DataType, typename IndexType, MatrixType Type = MatrixType::SYMMETRIC>
  149. Matrix<DataType, IndexType, Type> make_Matrix(IndexType s) {
  150. return Matrix<DataType, IndexType, Type>(new DataType[Matrix<DataType, IndexType, Type>::capacity(s)], s);
  151. }
  152. /**
  153. * A simple sparse matrix implementation.
  154. *
  155. * We use CSC format and provide get/set functionalities for each (i,j) item
  156. * on the matrix. We also provide a () overload using a proxy SpMatVal object.
  157. * This way the user can:
  158. * \code
  159. * auto v = A(3,4);
  160. * A(3, 4) = 7;
  161. * \endcode
  162. *
  163. * We also provide getCol() and getRow() functions witch return a viewer/iterator to rows and
  164. * columns of the matrix. In the case of a symmetric matrix instead of a row we return the
  165. * equivalent column. This way we gain speed due to CSC format nature.
  166. *
  167. * @tparam DataType The type for values
  168. * @tparam IndexType The type for indexes
  169. * @tparam Type The Matrix type (FULL or SYMMETRIC)
  170. */
  171. template<typename DataType, typename IndexType, MatrixType Type>
  172. struct SpMat {
  173. using dataType = DataType; //!< meta:export of underling data type
  174. using indexType = IndexType; //!< meta:export of underling index type
  175. static constexpr MatrixType matrixType = Type; //!< export of array type
  176. friend struct SpMatCol<DataType, IndexType>;
  177. friend struct SpMatRow<DataType, IndexType>;
  178. friend struct SpMatVal<DataType, IndexType>;
  179. /*!
  180. * \name Obj lifetime
  181. */
  182. //! @{
  183. //! Default ctor with optional memory allocations
  184. SpMat(IndexType n=IndexType{}, IndexType nnz=IndexType{}) :
  185. values(nnz, DataType{}),
  186. rows(nnz, IndexType{}),
  187. col_ptr((n)? n+1:2, IndexType{}),
  188. N(n),
  189. NNZ(nnz) { }
  190. //! A ctor using csc array data
  191. SpMat(IndexType n, IndexType nnz, const IndexType* row, const IndexType* col) :
  192. values(nnz, 1),
  193. rows(row, row+nnz),
  194. col_ptr(col, col+n+1),
  195. N(n),
  196. NNZ(nnz) { }
  197. //! ctor using csc array data with value array
  198. SpMat(IndexType n, IndexType nnz, const DataType* v, const IndexType* row, const IndexType* col) :
  199. values(v, v+nnz),
  200. rows(row, row+nnz),
  201. col_ptr(col, col+n+1),
  202. N(n),
  203. NNZ(nnz) { }
  204. //! ctor vectors of row/col and default value for values array
  205. SpMat(IndexType n, IndexType nnz, const DataType v, const std::vector<IndexType>& row, const std::vector<IndexType>& col) :
  206. values(nnz, v),
  207. rows (row),
  208. col_ptr(col),
  209. N(n),
  210. NNZ(nnz) { }
  211. //! move ctor
  212. SpMat(SpMat&& a) noexcept { moves(std::move(a)); }
  213. //! move
  214. SpMat& operator=(SpMat&& a) noexcept { moves(std::move(a)); return *this; }
  215. SpMat(const SpMat& a) = delete; //!< make sure there are no copies
  216. SpMat& operator=(const SpMat& a) = delete; //!< make sure there are no copies
  217. //! @}
  218. //! \name Data exposure
  219. //! @{
  220. //! \return the dimension of the matrix
  221. IndexType size() noexcept { return N; }
  222. //! After construction size configuration tool
  223. IndexType size(IndexType n) {
  224. col_ptr.resize(n+1);
  225. return N = n;
  226. }
  227. //! \return the NNZ of the matrix
  228. IndexType capacity() noexcept { return NNZ; }
  229. //! After construction NNZ size configuration tool
  230. IndexType capacity(IndexType nnz) {
  231. values.reserve(nnz);
  232. rows.reserve(nnz);
  233. return NNZ;
  234. }
  235. // getters for row arrays of the struct (unused)
  236. std::vector<DataType>& getValues() noexcept { return values; }
  237. std::vector<IndexType>& getRows() noexcept { return rows; }
  238. std::vector<IndexType>& getCols() noexcept { return col_ptr; }
  239. /*!
  240. * Return a proxy SpMatVal object with read and write capabilities.
  241. * @param i The row number
  242. * @param j The column number
  243. * @return tHE SpMatVal object
  244. */
  245. SpMatVal<DataType, IndexType> operator()(IndexType i, IndexType j) {
  246. return SpMatVal<DataType, IndexType>(this, get(i, j), i, j);
  247. }
  248. /*!
  249. * A read item functionality using binary search to find the correct row
  250. *
  251. * @param i The row number
  252. * @param j The column number
  253. * @return The value of the item or DataType{} if is not present.
  254. */
  255. DataType get(IndexType i, IndexType j) {
  256. IndexType idx; bool found;
  257. std::tie(idx, found) =find_idx(rows, col_ptr[j], col_ptr[j+1], i);
  258. return (found) ? values[idx] : 0;
  259. }
  260. /*!
  261. * A read item functionality using linear search to find the correct row
  262. *
  263. * @param i The row number
  264. * @param j The column number
  265. * @return The value of the item or DataType{} if is not present.
  266. */
  267. DataType get_lin(IndexType i, IndexType j) {
  268. IndexType idx; bool found;
  269. std::tie(idx, found) =find_place_idx(rows, col_ptr[j], col_ptr[j+1], i);
  270. return (found) ? values[idx] : 0;
  271. }
  272. /*!
  273. * A write item functionality.
  274. *
  275. * First we search if the matrix has already a value in (i, j) position.
  276. * If so we just change it to a new value. If not we add the item on the matrix.
  277. *
  278. * @note
  279. * When change a value, we don't increase the NNZ value of the struct. We expect the user has already
  280. * change the NNZ value to the right one using @see capacity() function. When adding a value we
  281. * increase the NNZ.
  282. *
  283. * @param i The row number
  284. * @param j The column number
  285. * @return The new value of the item .
  286. */
  287. DataType set(DataType v, IndexType i, IndexType j) {
  288. IndexType idx; bool found;
  289. std::tie(idx, found) = find_place_idx(rows, col_ptr[j], col_ptr[j+1], i);
  290. if (found)
  291. return values[idx] = v; // we don't change NNZ even if we write "0"
  292. else {
  293. values.insert(values.begin()+idx, v);
  294. rows.insert(rows.begin()+idx, i);
  295. std::transform(col_ptr.begin()+j+1, col_ptr.end(), col_ptr.begin()+j+1, [](IndexType it) {
  296. return ++it;
  297. });
  298. ++NNZ; // we increase the NNZ even if we write "0"
  299. return v;
  300. }
  301. }
  302. /*!
  303. * Get a view of a CSC column
  304. * @param j The column to get
  305. * @return The SpMatCol object @see SpMatCol
  306. */
  307. SpMatCol<DataType, IndexType> getCol(IndexType j) {
  308. return SpMatCol<DataType, IndexType>(this, col_ptr[j], col_ptr[j+1]);
  309. }
  310. /*!
  311. * Get a view of a CSC row
  312. *
  313. * In case of a SYMMETRIC matrix we can return a column instead.
  314. *
  315. * @param j The row to get
  316. * @return The SpMatCol object @see SpMatCol
  317. */
  318. template<MatrixType AT= Type>
  319. std::enable_if_t<AT==MatrixType::SYMMETRIC, SpMatCol<DataType, IndexType>>
  320. getRow(IndexType i) {
  321. return getCol(i);
  322. }
  323. /*!
  324. * Get a view of a CSC row
  325. *
  326. * @param j The row to get
  327. * @return The SpMatRow object @see SpMatRow
  328. */
  329. template<MatrixType AT= Type>
  330. std::enable_if_t<AT==MatrixType::FULL, SpMatCol<DataType, IndexType>>
  331. getRow(IndexType i) {
  332. return SpMatRow<DataType, IndexType>(this, i);
  333. }
  334. // values only iterator support
  335. DataType* begin() noexcept { return values.begin(); }
  336. DataType* end() noexcept { return values.end(); }
  337. //! @}
  338. //! A small iteration helper
  339. template<typename F, typename... Args>
  340. void for_each_in (IndexType begin, IndexType end, F&& lambda, Args&&... args) {
  341. for (IndexType it=begin ; it<end ; ++it) {
  342. std::forward<F>(lambda)(std::forward<Args>(args)..., it);
  343. }
  344. }
  345. // friend operations for printing
  346. template<typename D, typename I, MatrixType T> friend void print(SpMat<D, I, T>& mat);
  347. template<typename D, typename I, MatrixType T> friend void print_dense(SpMat<D, I, T>& mat);
  348. private:
  349. /*!
  350. * A small binary search implementation using index for begin-end instead of iterators.
  351. *
  352. * \param v Reference to vector to search
  353. * \param begin The vector's index to begin
  354. * \param end The vector's index to end
  355. * \param match What to search
  356. * \return An <index, status> pair.
  357. * index is the index of the item or end if not found
  358. * status is true if found, false otherwise
  359. */
  360. std::pair<IndexType, bool> find_idx(const std::vector<IndexType>& v, IndexType begin, IndexType end, IndexType match) {
  361. IndexType b = begin, e = end-1;
  362. while (b <= e) {
  363. IndexType m = (b+e)/2;
  364. if (v[m] == match) return std::make_pair(m, true);
  365. else if (b >= e) return std::make_pair(end, false);
  366. else {
  367. if (v[m] < match) b = m +1;
  368. else e = m -1;
  369. }
  370. }
  371. return std::make_pair(end, false);
  372. }
  373. /*!
  374. * find helper for set using index for begin-end instead of iterators.
  375. *
  376. * We search for the item or a place to add the item.
  377. * So we return the index if we find it. Otherwise we return the place to add it.
  378. *
  379. * \param v Reference to vector to search
  380. * \param begin The vector's index to begin
  381. * \param end The vector's index to end
  382. * \param match What to search
  383. * \return An <index, status> pair.
  384. * index is the index of the item or end if not found
  385. * status is true if found, false otherwise
  386. */
  387. std::pair<IndexType, bool> find_place_idx(const std::vector<IndexType>& v, IndexType begin, IndexType end, IndexType match) {
  388. for ( ; begin < end ; ++begin) {
  389. if (match == v[begin]) return std::make_pair(begin, true);
  390. else if (match < v[begin]) return std::make_pair(begin, false);
  391. }
  392. return std::make_pair(end, false);
  393. }
  394. // move helper
  395. void moves(SpMat&& src) noexcept {
  396. values = std::move(src.values);
  397. rows = std::move(src.rows);
  398. col_ptr = std::move(src.col_ptr);
  399. N = std::move(src.N); // redundant for primitives
  400. NNZ = std::move(src.NNZ); //
  401. }
  402. //! \name Data
  403. //! @{
  404. std::vector<DataType> values {}; //!< vector to store the values of the matrix
  405. std::vector<IndexType> rows{}; //!< vector to store the row information
  406. std::vector<IndexType> col_ptr{1,0}; //!< vector to store the column pointers
  407. IndexType N{0}; //!< The dimension of the matrix (square)
  408. IndexType NNZ{0}; //!< The NNZ (capacity of the matrix)
  409. //! @}
  410. };
  411. /*!
  412. * A view/iterator hybrid object for SpMat columns.
  413. *
  414. * This object provides access to a column of a SpMat. The public functionalities
  415. * allow data access using indexes instead of iterators. We prefer indexes over iterators
  416. * because we can apply the same index to different inner vector of SpMat without conversion.
  417. *
  418. * @tparam DataType
  419. * @tparam IndexType
  420. */
  421. template<typename DataType, typename IndexType>
  422. struct SpMatCol {
  423. using owner_t = SpMat<DataType, IndexType>;
  424. /*!
  425. * ctor using column pointers for begin-end. own is pointer to SpMat.
  426. */
  427. SpMatCol(owner_t* own, const IndexType begin, const IndexType end) noexcept :
  428. owner_(own), index_(begin), begin_(begin), end_(end) {
  429. vindex_ = vIndexCalc(index_);
  430. }
  431. SpMatCol() = default;
  432. SpMatCol(const SpMatCol&) = delete; //!< make sure there are no copies
  433. SpMatCol& operator=(const SpMatCol&)= delete; //!< make sure there are no copies
  434. SpMatCol(SpMatCol&&) = default;
  435. SpMatCol& operator=(SpMatCol&&) = default;
  436. //! a simple dereference operator, like an iterator
  437. DataType operator* () {
  438. return get();
  439. }
  440. //! Increment operator acts on index(), like an iterator
  441. SpMatCol& operator++ () { advance(); return *this; }
  442. SpMatCol& operator++ (int) { SpMatCol& p = *this; advance(); return p; }
  443. //! () operator acts as member access (like a view)
  444. DataType operator()(IndexType x) {
  445. return (x == index())? get() : DataType{};
  446. }
  447. //! = operator acts as member assignment (like a view)
  448. DataType operator= (DataType v) { return owner_->values[index_] = v; }
  449. // iterator like handlers
  450. // these return a virtual index value based on the items position on the full matrix
  451. // but the move of the index is just a ++ away.
  452. IndexType index() noexcept { return vindex_; }
  453. const IndexType index() const noexcept { return vindex_; }
  454. IndexType begin() noexcept { return vIndexCalc(begin_); }
  455. const IndexType begin() const noexcept { return vIndexCalc(begin_); }
  456. IndexType end() noexcept { return owner_->N; }
  457. const IndexType end() const noexcept { return owner_->N; }
  458. /*!
  459. * Multiplication operator
  460. *
  461. * We follow only the non-zero values and multiply only the common indexes.
  462. *
  463. * @tparam C Universal reference for the type right half site column
  464. *
  465. * @param c The right hand site matrix
  466. * @return The value of the inner product of two vectors
  467. * @note The time complexity is \$ O(nnz1+nnz2) \$.
  468. * Where the nnz is the max NNZ elements of the column of the matrix
  469. */
  470. template <typename C>
  471. DataType operator* (C&& c) {
  472. static_assert(std::is_same<remove_cvref_t<C>, SpMatCol<DataType, IndexType>>(), "");
  473. DataType v{};
  474. while (index() != end() && c.index() != c.end()) {
  475. if (index() < c.index()) advance(); // advance me
  476. else if (index() > c.index()) ++c; // advance other
  477. else { //index() == c.index()
  478. v += get() * *c; // multiply and advance both
  479. ++c;
  480. advance();
  481. }
  482. }
  483. return v;
  484. }
  485. private:
  486. //! small tool to increase the index pointers to SpMat matrix
  487. void advance() noexcept {
  488. ++index_;
  489. vindex_ = vIndexCalc(index_);
  490. }
  491. //! tool to translate between col_ptr indexes and SpMat "virtual" full matrix indexes
  492. IndexType vIndexCalc(IndexType idx) {
  493. return (idx < end_) ? owner_->rows[idx] : end();
  494. }
  495. //! small get tool
  496. DataType get() { return owner_->values[index_]; }
  497. owner_t* owner_ {nullptr}; //!< Pointer to owner SpMat. SpMatCol is just a view
  498. IndexType vindex_ {IndexType{}}; //!< Virtual index of full matrix
  499. IndexType index_ {IndexType{}}; //!< index to SpMat::rows
  500. IndexType begin_ {IndexType{}}; //!< beginning index of the column in SpMat::rows
  501. IndexType end_ {IndexType{}}; //!< ending index of the column in SpMat::rows
  502. };
  503. /*!
  504. * A view/iterator hybrid object for SpMat rows.
  505. *
  506. * This object provides access to a column of a SpMat. The public functionalities
  507. * allow data access using indexes instead of iterators. We prefer indexes over iterators
  508. * because we can apply the same index to different inner vector of SpMat without conversion.
  509. *
  510. * @tparam DataType
  511. * @tparam IndexType
  512. */
  513. template<typename DataType, typename IndexType>
  514. struct SpMatRow {
  515. using owner_t = SpMat<DataType, IndexType>;
  516. /*!
  517. * ctor using virtual full matrix row index. own is pointer to SpMat.
  518. */
  519. SpMatRow(owner_t* own, const IndexType row) noexcept :
  520. owner_(own), vindex_(IndexType{}), row_(row), index_(IndexType{}),
  521. begin_(IndexType{}), end_(owner_->NNZ) {
  522. // place begin
  523. while(begin_ != end_ && owner_->rows[begin_] != row_)
  524. ++begin_;
  525. // place index_ and vindex_
  526. if (owner_->rows[index_] != row_)
  527. advance();
  528. }
  529. SpMatRow() = default;
  530. SpMatRow(const SpMatRow&) = delete; //!< make sure there are no copies
  531. SpMatRow& operator=(const SpMatRow&)= delete; //!< make sure there are no copies
  532. SpMatRow(SpMatRow&&) = default;
  533. SpMatRow& operator=(SpMatRow&&) = default;
  534. //! a simple dereference operator, like an iterator
  535. DataType operator* () {
  536. return get();
  537. }
  538. //! Increment operator acts on index(), like an iterator
  539. //! here the increment is a O(N) process.
  540. SpMatRow& operator++ () { advance(); return *this; }
  541. SpMatRow& operator++ (int) { SpMatRow& p = *this; advance(); return p; }
  542. //! () operator acts as member access (like a view)
  543. DataType operator()(IndexType x) {
  544. return (x == index())? get() : DataType{};
  545. }
  546. //! = operator acts as member assignment (like a view)
  547. DataType operator= (DataType v) { return owner_->values[index_] = v; }
  548. // iterator like handlers
  549. // these return a virtual index value based on the items position on the full matrix
  550. // but the move of the index is just a ++ away.
  551. IndexType index() noexcept { return vindex_; }
  552. const IndexType index() const noexcept { return vindex_; }
  553. IndexType begin() noexcept { return vIndexCalc(begin_); }
  554. const IndexType begin() const noexcept { return vIndexCalc(begin_); }
  555. IndexType end() noexcept { return owner_->N; }
  556. const IndexType end() const noexcept { return owner_->N; }
  557. /*!
  558. * Multiplication operator
  559. *
  560. * We follow only the non-zero values and multiply only the common indexes.
  561. *
  562. * @tparam C Universal reference for the type right half site column
  563. *
  564. * @param c The right hand site matrix
  565. * @return The value of the inner product of two vectors
  566. * @note The time complexity is \$ O(N+nnz2) \$ and way heavier the ColxCol multiplication.
  567. * Where the nnz is the max NNZ elements of the column of the matrix
  568. */
  569. template <typename C>
  570. DataType operator* (C&& c) {
  571. static_assert(std::is_same<remove_cvref_t<C>, SpMatCol<DataType, IndexType>>(), "");
  572. DataType v{};
  573. while (index() != end() && c.index() != c.end()) {
  574. if (index() < c.index()) advance(); // advance me
  575. else if (index() > c.index()) ++c; // advance other
  576. else { //index() == c.index()
  577. v += get() * *c; // multiply and advance both
  578. ++c;
  579. advance();
  580. }
  581. }
  582. return v;
  583. }
  584. private:
  585. //! small tool to increase the index pointers to SpMat matrix
  586. //! We have to search the entire rows vector in SpMat to find the next
  587. //! virtual row position.
  588. //! time complexity O(N)
  589. void advance() noexcept {
  590. do
  591. ++index_;
  592. while(index_ != end_ && owner_->rows[index_] != row_);
  593. vindex_ = vIndexCalc(index_);
  594. }
  595. //! tool to translate between col_ptr indexes and SpMat "virtual" full matrix indexes
  596. IndexType vIndexCalc(IndexType idx) {
  597. for(IndexType i =0 ; i<(owner_->N+1) ; ++i)
  598. if (idx < owner_->col_ptr[i])
  599. return i-1;
  600. return end();
  601. }
  602. //! small get tool
  603. DataType get() { return owner_->values[index_]; }
  604. owner_t* owner_ {nullptr}; //!< Pointer to owner SpMat. SpMatCol is just a view
  605. IndexType vindex_ {IndexType{}}; //!< Virtual index of full matrix
  606. IndexType row_ {IndexType{}}; //!< The virtual full matrix row of the object
  607. IndexType index_ {IndexType{}}; //!< index to SpMat::rows
  608. IndexType begin_ {IndexType{}}; //!< beginning index of the column in SpMat::rows
  609. IndexType end_ {IndexType{}}; //!< ending index of the column in SpMat::rows
  610. };
  611. /*!
  612. * A proxy SpMat value object/view.
  613. *
  614. * This object acts as proxy to provide read/write access to an SpMat item.
  615. *
  616. * @tparam DataType The type of the values of the SpMat matrix
  617. * @tparam IndexType The type of the indexes of the SpMat matrix
  618. */
  619. template<typename DataType, typename IndexType>
  620. struct SpMatVal {
  621. using owner_t = SpMat<DataType, IndexType>;
  622. //!< ctor using all value-row-column data, plus a pointer to owner SpMat object
  623. SpMatVal(owner_t* own, DataType v, IndexType i, IndexType j) :
  624. owner_(own), v_(v), i_(i), j_(j) { }
  625. SpMatVal() = default;
  626. SpMatVal(const SpMatVal&) = delete; //!< make sure there are no copies
  627. SpMatVal& operator=(const SpMatVal&) = delete; //!< make sure there are no copies
  628. SpMatVal(SpMatVal&&) = default;
  629. SpMatVal& operator=(SpMatVal&&) = default;
  630. //! Operator to return the DataType value implicitly
  631. operator DataType() { return v_; }
  632. //! Operator to write back to owner the assigned value
  633. //! for ex: A(2,3) = 5;
  634. SpMatVal& operator=(DataType v) {
  635. v_ = v;
  636. owner_->set(v_, i_, j_);
  637. return *this;
  638. }
  639. private:
  640. owner_t* owner_{nullptr}; //!< Pointer to owner SpMat. SpMatVal is just a view.
  641. DataType v_{DataType{}}; //!< The value of the row-column pair (for speed)
  642. IndexType i_{IndexType{}}; //!< The row
  643. IndexType j_{IndexType{}}; //!< the column
  644. };
  645. //! enumerator for input matrix type.
  646. enum class InputMatrix{ UNSPECIFIED, GENERATE, MTX };
  647. //! enumerator for output handling
  648. enum class OutputMode{ STD, FILE };
  649. /*!
  650. * Session option for each invocation of the executable
  651. */
  652. struct session_t {
  653. InputMatrix inputMatrix {InputMatrix::UNSPECIFIED}; //!< Source of the matrix
  654. std::ifstream mtxFile {}; //!< matrix file in MatrixMarket format
  655. std::size_t gen_size {}; //!< size of the matrix if we select to generate a random one
  656. double gen_prob {}; //!< probability of the binomial distribution for the matrix
  657. //!< if we generate one
  658. OutputMode outputMode {OutputMode::STD}; //!< Type of the output file
  659. std::ofstream outFile {}; //!< File to use for output
  660. std::size_t max_threads {}; //!< Maximum threads to use
  661. std::size_t repeat {1}; //!< How many times we execute the calculations part
  662. bool timing {false}; //!< Enable timing prints of the program
  663. bool verbose {false}; //!< Flag to enable verbose output to stdout
  664. #if CODE_VERSION == 3
  665. bool makeSymmetric {false}; //!< symmetric matrix creation flag (true by default)
  666. #else
  667. bool makeSymmetric {true}; //!< symmetric matrix creation flag (true by default)
  668. #endif
  669. bool validate_mtx {false}; //!< Flag to request mtx input data triangular validation.
  670. bool print_count {false}; //!< Flag to request total count printing
  671. bool mtx_print {false}; //!< matrix print flag
  672. std::size_t mtx_print_size {}; //!< matrix print size
  673. bool dynamic {false}; //!< Selects dynamic scheduling for OpenMP and pthreads.
  674. };
  675. extern session_t session;
  676. #endif /* IMPL_HPP_ */