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.
 
 
 
 
 
 

282 lines
8.1 KiB

  1. /*!
  2. * \file utils.h
  3. * \brief Utilities to handle matrix files, chrono, etc...
  4. *
  5. * \author
  6. * Christos Choutouridis AEM:8997
  7. * <cchoutou@ece.auth.gr>
  8. */
  9. #ifndef UTILS_H_
  10. #define UTILS_H_
  11. #include <string>
  12. #include <sstream>
  13. #include <iostream>
  14. #include <chrono>
  15. #include <random>
  16. #include <impl.hpp>
  17. #include <config.h>
  18. /*!
  19. * A small RAII utility to memory allocation arrays.
  20. * @tparam T The type of pointer for the memory
  21. */
  22. template <typename T>
  23. struct buffer_t {
  24. buffer_t(size_t s) { p = new T[s]; }
  25. ~buffer_t() { delete[] p; }
  26. buffer_t() = default;
  27. buffer_t(buffer_t&&) = default;
  28. buffer_t& operator=(buffer_t&&) = default;
  29. buffer_t(const buffer_t&) = delete;
  30. buffer_t& operator=(const buffer_t&) = delete;
  31. T* allocate(size_t s) { return p = new T[s]; }
  32. T* operator() () { return p; }
  33. T& operator[] (size_t i){ return p[i]; }
  34. private:
  35. T* p{nullptr};
  36. };
  37. /*!
  38. * A toolbox for MatrixMarket format handling
  39. */
  40. struct Mtx {
  41. /*!
  42. * A template version of the coo2csc function provided by PDS lab stuff.
  43. */
  44. template<typename I>
  45. static void coo2csc(I *row, I *col, I const* row_coo, I const* col_coo, I nnz, I n, I isOneBased) {
  46. // ----- cannot assume that input is already 0!
  47. for (I l = 0; l < n+1; l++) col[l] = 0;
  48. // ----- find the correct column sizes
  49. for (I l = 0; l < nnz; l++)
  50. col[col_coo[l] - isOneBased]++;
  51. // ----- cumulative sum
  52. for (I i = 0, cumsum = 0; i < n; i++) {
  53. I temp = col[i];
  54. col[i] = cumsum;
  55. cumsum += temp;
  56. }
  57. col[n] = nnz;
  58. // ----- copy the row indices to the correct place
  59. for (I l = 0; l < nnz; l++) {
  60. I col_l;
  61. col_l = col_coo[l] - isOneBased;
  62. I dst = col[col_l];
  63. row[dst] = row_coo[l] - isOneBased;
  64. col[col_l]++;
  65. }
  66. // ----- revert the column pointers
  67. for (I i = 0, last = 0; i < n; i++) {
  68. I temp = col[i];
  69. col[i] = last;
  70. last = temp;
  71. }
  72. }
  73. /*!
  74. * Utility to check if a matrix input is strictly triangular or not.
  75. * @tparam I Index type
  76. * @param file Reference to input file stream
  77. * @return The status of the operation
  78. */
  79. template<typename I>
  80. static bool is_triangular (std::ifstream& file) {
  81. std::string line, token;
  82. enum state_en {HEADER, SIZE, DATA} state = HEADER;
  83. enum LU_t {Z, LOWER, UPPER} LU = Z;
  84. while (std::getline (file, line, '\n')) {
  85. std::stringstream ss(line);
  86. switch (state) {
  87. case HEADER:
  88. ss >> token;
  89. if (token != "%%MatrixMarket") return false;
  90. else state = SIZE;
  91. break;
  92. case SIZE:
  93. if (line[0] == '%') continue;
  94. else state = DATA;
  95. break;
  96. case DATA:
  97. if (line[0] == '%') continue;
  98. I i, j;
  99. ss >> i >> j;
  100. switch (LU) {
  101. case Z: LU = (i<j) ? UPPER: LOWER; break;
  102. case LOWER: if (i<=j) return false; break;
  103. case UPPER: if (j<=i) return false; break;
  104. }
  105. break;
  106. }
  107. }
  108. file.clear(); // rewind
  109. file.seekg(0);
  110. return true;
  111. }
  112. /*!
  113. * A utility to load an MatrixMarket file to memory
  114. * @tparam DataT The data type
  115. * @tparam IndexT The indexes type
  116. * @param M Reference to matrix for output
  117. * @param file Reference to input file stream to read from
  118. * @return The status of the operation
  119. */
  120. template<typename DataT, typename IndexT, MatrixType MatrixT>
  121. static bool load (SpMat<DataT, IndexT, MatrixT>& M, std::ifstream& file) {
  122. std::string line, token;
  123. enum state_en {HEADER, SIZE, DATA} state = HEADER;
  124. enum LU_t {Z, LOWER, UPPER} LU = Z;
  125. IndexT n1, n2, nnz;
  126. buffer_t<IndexT> col{}, row{}, coo_col{}, coo_row{};
  127. IndexT cnt{};
  128. while (std::getline (file, line, '\n')) {
  129. std::stringstream ss(line);
  130. switch (state) {
  131. case HEADER:
  132. ss >> token;
  133. if (token != "%%MatrixMarket") return false;
  134. else state = SIZE;
  135. break;
  136. case SIZE:
  137. if (line[0] == '%') continue;
  138. else {
  139. ss >> n1 >> n2 >> nnz;
  140. if (session.makeSymmetric)
  141. nnz *= 2;
  142. col.allocate(nnz);
  143. row.allocate(nnz);
  144. coo_col.allocate(nnz);
  145. coo_row.allocate(nnz);
  146. state = DATA;
  147. }
  148. break;
  149. case DATA:
  150. if (line[0] == '%') continue;
  151. IndexT i, j;
  152. ss >> i >> j;
  153. if (LU == Z) {
  154. LU = (i<j) ? UPPER: LOWER;
  155. }
  156. // ignore all values outside the triangle area
  157. if ((LU==LOWER && j<i) || (LU==UPPER && i<j)) {
  158. coo_row[cnt] = i;
  159. coo_col[cnt++] = j;
  160. if (session.makeSymmetric) {
  161. coo_row[cnt] = j;
  162. coo_col[cnt++] = i;
  163. }
  164. }
  165. break;
  166. }
  167. }
  168. if (cnt) {
  169. // convert and construct
  170. coo2csc(&row[0], &col[0], &coo_row[0], &coo_col[0], cnt, n1, 1);
  171. M = SpMat<DataT, IndexT, MatrixT>(n1, cnt, &row[0], &col[0]);
  172. return true;
  173. }
  174. return false;
  175. }
  176. };
  177. /*!
  178. * A small timing utility based on chrono.
  179. */
  180. struct Timing{
  181. using Tpoint = std::chrono::steady_clock::time_point;
  182. using microseconds = std::chrono::microseconds;
  183. using milliseconds = std::chrono::milliseconds;
  184. using seconds = std::chrono::seconds;
  185. //! tool to mark the starting point
  186. Tpoint start () noexcept { return start_ = std::chrono::steady_clock::now(); }
  187. //! tool to mark the ending point
  188. Tpoint stop () noexcept { return stop_ = std::chrono::steady_clock::now(); }
  189. auto dt () noexcept {
  190. return std::chrono::duration_cast<std::chrono::microseconds>(stop_ - start_).count();
  191. }
  192. //! tool to print the time interval
  193. void print_dt (const char* what) noexcept {
  194. if (session.timing) {
  195. auto t = stop_ - start_;
  196. if (std::chrono::duration_cast<microseconds>(t).count() < 10000)
  197. std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<microseconds>(t).count()) << " [usec]\n";
  198. else if (std::chrono::duration_cast<milliseconds>(t).count() < 10000)
  199. std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<milliseconds>(t).count()) << " [msec]\n";
  200. else
  201. std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<seconds>(t).count()) << " [sec]\n";
  202. }
  203. }
  204. private:
  205. Tpoint start_;
  206. Tpoint stop_;
  207. };
  208. /*!
  209. * A Logger for entire program.
  210. */
  211. struct Log {
  212. struct Endl {} endl; //!< a tag object to to use it as a new line request.
  213. //! We provide logging via << operator
  214. template<typename T>
  215. Log& operator<< (T&& t) {
  216. if (session.verbose) {
  217. if (line_) {
  218. std::cout << "[Log]: " << t;
  219. line_ = false;
  220. }
  221. else
  222. std::cout << t;
  223. }
  224. return *this;
  225. }
  226. // overload for special end line handling
  227. Log& operator<< (Endl e) { (void)e;
  228. if (session.verbose) {
  229. std::cout << '\n';
  230. line_ = true;
  231. }
  232. return *this;
  233. }
  234. private:
  235. bool line_ {true};
  236. };
  237. extern Log logger;
  238. //! Total count result printing function
  239. template<typename F>
  240. void triangle_out (value_t s, F&& f) {
  241. f << "Total triangles: " << s << '\n';
  242. }
  243. //! vector out result printing function
  244. template<typename F>
  245. void vector_out (std::vector<value_t>& v, F&& f) {
  246. size_t idx{};
  247. f << "id,c3\n";
  248. for (auto& it : v) f << idx++ <<',' << it << '\n';
  249. f << '\n';
  250. }
  251. /*
  252. * Public non-template api.
  253. * We use matrix alias template. So it has to be defined somewhere
  254. */
  255. void init_ER_graph (matrix& A, double p);
  256. void print_graph (matrix& A);
  257. void threads_info ();
  258. #endif /* UTILS_H_ */