|
- /*!
- * \file utils.h
- * \brief Utilities to handle matrix files, chrono, etc...
- *
- * \author
- * Christos Choutouridis AEM:8997
- * <cchoutou@ece.auth.gr>
- */
- #ifndef UTILS_H_
- #define UTILS_H_
-
- #include <string>
- #include <sstream>
- #include <iostream>
- #include <chrono>
- #include <random>
- #include <impl.hpp>
- #include <config.h>
-
- /*!
- * A small RAII utility to memory allocation arrays.
- * @tparam T The type of pointer for the memory
- */
- template <typename T>
- struct buffer_t {
- buffer_t(size_t s) { p = new T[s]; }
- ~buffer_t() { delete[] p; }
- buffer_t() = default;
- buffer_t(buffer_t&&) = default;
- buffer_t& operator=(buffer_t&&) = default;
- buffer_t(const buffer_t&) = delete;
- buffer_t& operator=(const buffer_t&) = delete;
-
- T* allocate(size_t s) { return p = new T[s]; }
- T* operator() () { return p; }
- T& operator[] (size_t i){ return p[i]; }
- private:
- T* p{nullptr};
- };
-
- /*!
- * A toolbox for MatrixMarket format handling
- */
- struct Mtx {
-
- /*!
- * A template version of the coo2csc function provided by PDS lab stuff.
- */
- template<typename I>
- static void coo2csc(I *row, I *col, I const* row_coo, I const* col_coo, I nnz, I n, I isOneBased) {
- // ----- cannot assume that input is already 0!
- for (I l = 0; l < n+1; l++) col[l] = 0;
-
- // ----- find the correct column sizes
- for (I l = 0; l < nnz; l++)
- col[col_coo[l] - isOneBased]++;
-
- // ----- cumulative sum
- for (I i = 0, cumsum = 0; i < n; i++) {
- I temp = col[i];
- col[i] = cumsum;
- cumsum += temp;
- }
- col[n] = nnz;
- // ----- copy the row indices to the correct place
- for (I l = 0; l < nnz; l++) {
- I col_l;
- col_l = col_coo[l] - isOneBased;
-
- I dst = col[col_l];
- row[dst] = row_coo[l] - isOneBased;
-
- col[col_l]++;
- }
- // ----- revert the column pointers
- for (I i = 0, last = 0; i < n; i++) {
- I temp = col[i];
- col[i] = last;
- last = temp;
- }
- }
-
- /*!
- * Utility to check if a matrix input is strictly triangular or not.
- * @tparam I Index type
- * @param file Reference to input file stream
- * @return The status of the operation
- */
- template<typename I>
- static bool is_triangular (std::ifstream& file) {
- std::string line, token;
- enum state_en {HEADER, SIZE, DATA} state = HEADER;
- enum LU_t {Z, LOWER, UPPER} LU = Z;
-
- while (std::getline (file, line, '\n')) {
- std::stringstream ss(line);
- switch (state) {
- case HEADER:
- ss >> token;
- if (token != "%%MatrixMarket") return false;
- else state = SIZE;
- break;
- case SIZE:
- if (line[0] == '%') continue;
- else state = DATA;
- break;
- case DATA:
- if (line[0] == '%') continue;
- I i, j;
- ss >> i >> j;
- switch (LU) {
- case Z: LU = (i<j) ? UPPER: LOWER; break;
- case LOWER: if (i<=j) return false; break;
- case UPPER: if (j<=i) return false; break;
- }
- break;
- }
- }
- file.clear(); // rewind
- file.seekg(0);
- return true;
- }
-
- /*!
- * A utility to load an MatrixMarket file to memory
- * @tparam DataT The data type
- * @tparam IndexT The indexes type
- * @param M Reference to matrix for output
- * @param file Reference to input file stream to read from
- * @return The status of the operation
- */
- template<typename DataT, typename IndexT, MatrixType MatrixT>
- static bool load (SpMat<DataT, IndexT, MatrixT>& M, std::ifstream& file) {
- std::string line, token;
- enum state_en {HEADER, SIZE, DATA} state = HEADER;
- enum LU_t {Z, LOWER, UPPER} LU = Z;
- IndexT n1, n2, nnz;
- buffer_t<IndexT> col{}, row{}, coo_col{}, coo_row{};
-
- IndexT cnt{};
- while (std::getline (file, line, '\n')) {
- std::stringstream ss(line);
- switch (state) {
- case HEADER:
- ss >> token;
- if (token != "%%MatrixMarket") return false;
- else state = SIZE;
- break;
- case SIZE:
- if (line[0] == '%') continue;
- else {
- ss >> n1 >> n2 >> nnz;
- if (session.makeSymmetric)
- nnz *= 2;
- col.allocate(nnz);
- row.allocate(nnz);
- coo_col.allocate(nnz);
- coo_row.allocate(nnz);
- state = DATA;
- }
- break;
- case DATA:
- if (line[0] == '%') continue;
- IndexT i, j;
- ss >> i >> j;
- if (LU == Z) {
- LU = (i<j) ? UPPER: LOWER;
- }
- // ignore all values outside the triangle area
- if ((LU==LOWER && j<i) || (LU==UPPER && i<j)) {
- coo_row[cnt] = i;
- coo_col[cnt++] = j;
- if (session.makeSymmetric) {
- coo_row[cnt] = j;
- coo_col[cnt++] = i;
- }
- }
- break;
- }
- }
- if (cnt) {
- // convert and construct
- coo2csc(&row[0], &col[0], &coo_row[0], &coo_col[0], cnt, n1, 1);
- M = SpMat<DataT, IndexT, MatrixT>(n1, cnt, &row[0], &col[0]);
- return true;
- }
- return false;
- }
- };
-
- /*!
- * A small timing utility based on chrono.
- */
- struct Timing{
- using Tpoint = std::chrono::steady_clock::time_point;
- using microseconds = std::chrono::microseconds;
- using milliseconds = std::chrono::milliseconds;
- using seconds = std::chrono::seconds;
-
- //! tool to mark the starting point
- Tpoint start () noexcept { return start_ = std::chrono::steady_clock::now(); }
- //! tool to mark the ending point
- Tpoint stop () noexcept { return stop_ = std::chrono::steady_clock::now(); }
-
- auto dt () noexcept {
- return std::chrono::duration_cast<std::chrono::microseconds>(stop_ - start_).count();
- }
- //! tool to print the time interval
- void print_dt (const char* what) noexcept {
- if (session.timing) {
- auto t = stop_ - start_;
- if (std::chrono::duration_cast<microseconds>(t).count() < 10000)
- std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<microseconds>(t).count()) << " [usec]\n";
- else if (std::chrono::duration_cast<milliseconds>(t).count() < 10000)
- std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<milliseconds>(t).count()) << " [msec]\n";
- else
- std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast<seconds>(t).count()) << " [sec]\n";
- }
- }
- private:
- Tpoint start_;
- Tpoint stop_;
- };
-
- /*!
- * A Logger for entire program.
- */
- struct Log {
- struct Endl {} endl; //!< a tag object to to use it as a new line request.
-
- //! We provide logging via << operator
- template<typename T>
- Log& operator<< (T&& t) {
- if (session.verbose) {
- if (line_) {
- std::cout << "[Log]: " << t;
- line_ = false;
- }
- else
- std::cout << t;
- }
- return *this;
- }
- // overload for special end line handling
- Log& operator<< (Endl e) { (void)e;
- if (session.verbose) {
- std::cout << '\n';
- line_ = true;
- }
- return *this;
- }
- private:
- bool line_ {true};
- };
-
- extern Log logger;
-
- //! Total count result printing function
- template<typename F>
- void triangle_out (value_t s, F&& f) {
- f << "Total triangles: " << s << '\n';
- }
-
- //! vector out result printing function
- template<typename F>
- void vector_out (std::vector<value_t>& v, F&& f) {
- size_t idx{};
- f << "id,c3\n";
- for (auto& it : v) f << idx++ <<',' << it << '\n';
- f << '\n';
- }
-
- /*
- * Public non-template api.
- * We use matrix alias template. So it has to be defined somewhere
- */
- void init_ER_graph (matrix& A, double p);
- void print_graph (matrix& A);
- void threads_info ();
-
- #endif /* UTILS_H_ */
|