A triangle counting assignment for A.U.TH Parallel and distributed systems class.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

520 Zeilen
17 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 declerations
  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 t use 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. template<typename DataType, typename IndexType>
  153. using CooVal = std::tuple<DataType, IndexType, IndexType>;
  154. template<typename DataType, typename IndexType, MatrixType Type>
  155. struct SpMat {
  156. using dataType = DataType; //!< meta:export of underling data type
  157. using indexType = IndexType; //!< meta:export of underling index type
  158. static constexpr MatrixType matrixType = Type; //!< export of array type
  159. friend class SpMatCol<DataType, IndexType>;
  160. friend class SpMatRow<DataType, IndexType>;
  161. friend class SpMatVal<DataType, IndexType>;
  162. /*!
  163. * \name Obj lifetime
  164. */
  165. //! @{
  166. //! allocation with init value ctor
  167. SpMat(IndexType n=IndexType{}, IndexType nnz=IndexType{}) :
  168. values(nnz, DataType{}),
  169. rows(nnz, IndexType{}),
  170. col_ptr((n)? n+1:2, IndexType{}),
  171. N(n),
  172. NNZ(nnz) { }
  173. SpMat(IndexType n, IndexType nnz, const IndexType* row, const IndexType* col) :
  174. values(nnz, 1),
  175. rows(row, row+nnz),
  176. col_ptr(col, col+n+1),
  177. N(n),
  178. NNZ(nnz) { }
  179. SpMat(IndexType n, IndexType nnz, const DataType* v, const IndexType* row, const IndexType* col) :
  180. values(v, v+nnz),
  181. rows(row, row+nnz),
  182. col_ptr(col, col+n+1),
  183. N(n),
  184. NNZ(nnz) { }
  185. SpMat(IndexType n, IndexType nnz, const DataType v, const std::vector<IndexType>& row, const std::vector<IndexType>& col) :
  186. values(nnz, v),
  187. rows (row),
  188. col_ptr(col),
  189. N(n),
  190. NNZ(nnz) { }
  191. //! move ctor
  192. SpMat(SpMat&& a) noexcept { moves(std::move(a)); }
  193. //! move
  194. SpMat& operator=(SpMat&& a) noexcept { moves(std::move(a)); return *this; }
  195. SpMat(const SpMat& a) = delete; //!< No copy ctor
  196. SpMat& operator=(const SpMat& a) = delete; //!< No copy assignment
  197. //! @}
  198. //! \name Data exposure
  199. //! @{
  200. IndexType size() noexcept { return N; }
  201. IndexType size(IndexType n) {
  202. col_ptr.resize(n+1);
  203. return N = n;
  204. }
  205. IndexType capacity() noexcept { return NNZ; }
  206. IndexType capacity(IndexType nnz) {
  207. values.reserve(nnz);
  208. rows.reserve(nnz);
  209. return NNZ;
  210. }
  211. std::vector<IndexType>& getRows() noexcept { return rows; }
  212. std::vector<IndexType>& getCols() noexcept { return col_ptr; }
  213. SpMatVal<DataType, IndexType> operator()(IndexType i, IndexType j) {
  214. return SpMatVal<DataType, IndexType>(this, get(i, j), i, j);
  215. }
  216. DataType get(IndexType i, IndexType j) {
  217. IndexType idx;
  218. bool found;
  219. std::tie(idx, found) =find_idx(rows, col_ptr[j], col_ptr[j+1], i);
  220. return (found) ? values[idx] : 0;
  221. }
  222. DataType set(DataType v, IndexType i, IndexType j) {
  223. IndexType idx; bool found;
  224. std::tie(idx, found) = find_idx(rows, col_ptr[j], col_ptr[j+1], i);
  225. if (found)
  226. return values[idx] = v; // we don't change NNZ even if we write "0"
  227. else {
  228. values.insert(values.begin()+idx, v);
  229. rows.insert(rows.begin()+idx, i);
  230. std::transform(col_ptr.begin()+j+1, col_ptr.end(), col_ptr.begin()+j+1, [](IndexType it) {
  231. return ++it;
  232. });
  233. ++NNZ; // we increase the NNZ even if we write "0"
  234. return v;
  235. }
  236. }
  237. SpMatCol<DataType, IndexType> getCol(IndexType j) {
  238. return SpMatCol<DataType, IndexType>(this, col_ptr[j], col_ptr[j+1]);
  239. }
  240. template<MatrixType AT= Type>
  241. std::enable_if_t<AT==MatrixType::SYMMETRIC, SpMatCol<DataType, IndexType>>
  242. getRow(IndexType i) {
  243. return getCol(i);
  244. }
  245. template<MatrixType AT= Type>
  246. std::enable_if_t<AT==MatrixType::FULL, SpMatCol<DataType, IndexType>>
  247. getRow(IndexType i) {
  248. return SpMatRow<DataType, IndexType>(this, i);
  249. }
  250. // iterator support
  251. DataType* begin() noexcept { return values.begin(); }
  252. DataType* end() noexcept { return values.end(); }
  253. //! @}
  254. /*!
  255. * \name Safe iteration API
  256. *
  257. * This api automates the iteration over the array based on
  258. * MatrixType
  259. */
  260. //! @{
  261. template<typename F, typename... Args>
  262. void for_each_in (IndexType begin, IndexType end, F&& lambda, Args&&... args) {
  263. for (IndexType it=begin ; it<end ; ++it) {
  264. std::forward<F>(lambda)(std::forward<Args>(args)..., it);
  265. }
  266. }
  267. //! @}
  268. // operations
  269. template<typename D, typename I, MatrixType T> friend void print(SpMat<D, I, T>& mat);
  270. template<typename D, typename I, MatrixType T> friend void print_dense(SpMat<D, I, T>& mat);
  271. private:
  272. // index-find helper
  273. std::pair<IndexType, bool> find_idx(const std::vector<IndexType>& v, IndexType begin, IndexType end, IndexType match) {
  274. for ( ; begin < end ; ++begin) {
  275. if (match == v[begin]) return std::make_pair(begin, true);
  276. else if (match < v[begin]) return std::make_pair(begin, false);
  277. }
  278. return std::make_pair(end, false);
  279. }
  280. // move helper
  281. void moves(SpMat&& src) noexcept {
  282. values = std::move(src.values);
  283. rows = std::move(src.rows);
  284. col_ptr = std::move(src.col_ptr);
  285. N = std::move(src.N); // redundant for primitives
  286. NNZ = std::move(src.NNZ); //
  287. }
  288. //! \name Data
  289. //! @{
  290. std::vector<DataType> values {};
  291. std::vector<IndexType> rows{};
  292. std::vector<IndexType> col_ptr{1,0};
  293. IndexType N{0};
  294. IndexType NNZ{0};
  295. //! @}
  296. };
  297. template<typename DataType, typename IndexType>
  298. struct SpMatCol {
  299. using owner_t = SpMat<DataType, IndexType>;
  300. SpMatCol(owner_t* own, const IndexType begin, const IndexType end) noexcept :
  301. owner_(own), index_(begin), begin_(begin), end_(end) {
  302. vindex_ = vIndexCalc(index_);
  303. }
  304. SpMatCol() = default;
  305. SpMatCol(const SpMatCol&) = delete;
  306. SpMatCol& operator=(const SpMatCol&)= delete;
  307. SpMatCol(SpMatCol&&) = default;
  308. SpMatCol& operator=(SpMatCol&&) = default;
  309. DataType operator* () {
  310. return get();
  311. }
  312. SpMatCol& operator++ () { advance(); return *this; }
  313. SpMatCol& operator++ (int) { SpMatCol& p = *this; advance(); return p; }
  314. DataType operator()(IndexType x) {
  315. return (x == index())? get() : DataType{};
  316. }
  317. DataType operator= (DataType v) { return owner_->values[index_] = v; }
  318. IndexType index() noexcept { return vindex_; }
  319. const IndexType index() const noexcept { return vindex_; }
  320. IndexType begin() noexcept { return vIndexCalc(begin_); }
  321. const IndexType begin() const noexcept { return vIndexCalc(begin_); }
  322. IndexType end() noexcept { return owner_->N; }
  323. const IndexType end() const noexcept { return owner_->N; }
  324. template <typename C>
  325. DataType operator* (C&& c) {
  326. static_assert(std::is_same<remove_cvref_t<C>, SpMatCol<DataType, IndexType>>(), "");
  327. DataType v{};
  328. while (index() != end() && c.index() != c.end()) {
  329. if (index() < c.index()) advance();
  330. else if (index() > c.index()) ++c;
  331. else { //index() == c.index()
  332. v += get() * *c;
  333. ++c;
  334. advance();
  335. }
  336. }
  337. return v;
  338. }
  339. private:
  340. void advance() noexcept {
  341. ++index_;
  342. vindex_ = vIndexCalc(index_);
  343. }
  344. IndexType vIndexCalc(IndexType idx) {
  345. return (idx < end_) ? owner_->rows[idx] : end();
  346. }
  347. DataType get() { return owner_->values[index_]; }
  348. owner_t* owner_{nullptr};
  349. IndexType vindex_ {IndexType{}};
  350. IndexType index_{IndexType{}};
  351. IndexType begin_{IndexType{}};
  352. IndexType end_{IndexType{}};
  353. };
  354. template<typename DataType, typename IndexType>
  355. struct SpMatRow {
  356. using owner_t = SpMat<DataType, IndexType>;
  357. SpMatRow(owner_t* own, const IndexType row) noexcept :
  358. owner_(own), vindex_(IndexType{}), row_(row), index_(IndexType{}),
  359. begin_(IndexType{}), end_(owner_->NNZ) {
  360. // place begin
  361. while(begin_ != end_ && owner_->rows[begin_] != row_)
  362. ++begin_;
  363. // place index_ and vindex_
  364. if (owner_->rows[index_] != row_)
  365. advance();
  366. }
  367. SpMatRow() = default;
  368. SpMatRow(const SpMatRow&) = delete;
  369. SpMatRow& operator=(const SpMatRow&)= delete;
  370. SpMatRow(SpMatRow&&) = default;
  371. SpMatRow& operator=(SpMatRow&&) = default;
  372. DataType operator* () {
  373. return get();
  374. }
  375. SpMatRow& operator++ () { advance(); return *this; }
  376. SpMatRow& operator++ (int) { SpMatRow& p = *this; advance(); return p; }
  377. DataType operator()(IndexType x) {
  378. return (x == index())? get() : DataType{};
  379. }
  380. DataType operator= (DataType v) { return owner_->values[index_] = v; }
  381. IndexType index() noexcept { return vindex_; }
  382. const IndexType index() const noexcept { return vindex_; }
  383. IndexType begin() noexcept { return vIndexCalc(begin_); }
  384. const IndexType begin() const noexcept { return vIndexCalc(begin_); }
  385. IndexType end() noexcept { return owner_->N; }
  386. const IndexType end() const noexcept { return owner_->N; }
  387. template <typename C>
  388. DataType operator* (C&& c) {
  389. static_assert(std::is_same<remove_cvref_t<C>, SpMatCol<DataType, IndexType>>(), "");
  390. DataType v{};
  391. while (index() != end() && c.index() != c.end()) {
  392. if (index() < c.index()) advance();
  393. else if (index() > c.index()) ++c;
  394. else { //index() == c.index()
  395. v += get()* *c;
  396. ++c;
  397. advance();
  398. }
  399. }
  400. return v;
  401. }
  402. private:
  403. void advance() noexcept {
  404. do
  405. ++index_;
  406. while(index_ != end_ && owner_->rows[index_] != row_);
  407. vindex_ = vIndexCalc(index_);
  408. }
  409. IndexType vIndexCalc(IndexType idx) {
  410. for(IndexType i =0 ; i<(owner_->N+1) ; ++i)
  411. if (idx < owner_->col_ptr[i])
  412. return i-1;
  413. return end();
  414. }
  415. DataType get() { return owner_->values[index_]; }
  416. owner_t* owner_ {nullptr};
  417. IndexType vindex_ {IndexType{}};
  418. IndexType row_ {IndexType{}};
  419. IndexType index_ {IndexType{}};
  420. IndexType begin_ {IndexType{}};
  421. IndexType end_ {IndexType{}};
  422. };
  423. template<typename DataType, typename IndexType>
  424. struct SpMatVal {
  425. using owner_t = SpMat<DataType, IndexType>;
  426. SpMatVal(owner_t* own, DataType v, IndexType i, IndexType j) :
  427. owner_(own), v_(v), i_(i), j_(j) { }
  428. SpMatVal() = default;
  429. SpMatVal(const SpMatVal&) = delete;
  430. SpMatVal& operator=(const SpMatVal&) = delete;
  431. SpMatVal(SpMatVal&&) = default;
  432. SpMatVal& operator=(SpMatVal&&) = default;
  433. operator DataType() { return v_; }
  434. SpMatVal& operator=(DataType v) {
  435. v_ = v;
  436. owner_->set(v_, i_, j_);
  437. return *this;
  438. }
  439. private:
  440. owner_t* owner_{nullptr};;
  441. DataType v_{DataType{}};
  442. IndexType i_{IndexType{}};
  443. IndexType j_{IndexType{}};
  444. };
  445. enum class InputMatrix{
  446. GENERATE,
  447. MTX
  448. };
  449. /*!
  450. * Session option for each invocation of the executable
  451. */
  452. struct session_t {
  453. std::size_t size {0};
  454. double probability {0};
  455. InputMatrix inputMatrix {InputMatrix::GENERATE};
  456. std::ifstream mtxFile {};
  457. std::size_t print_size {80};
  458. bool timing {false};
  459. bool print {false};
  460. bool makeSymmetric {false};
  461. };
  462. extern session_t session;
  463. #endif /* IMPL_HPP_ */