A triangle counting assignment for A.U.TH Parallel and distributed systems class.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

739 lignes
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_ */