/*! * \file utils.h * \brief Utilities to handle matrix files, chrono, etc... * * \author * Christos Choutouridis AEM:8997 * */ #ifndef UTILS_H_ #define UTILS_H_ #include #include #include #include #include #include #include /*! * A small RAII utility to memory allocation arrays. * @tparam T The type of pointer for the memory */ template 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 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 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 static bool load (SpMat& 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 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(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(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(t).count() < 10000) std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast(t).count()) << " [usec]\n"; else if (std::chrono::duration_cast(t).count() < 10000) std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast(t).count()) << " [msec]\n"; else std::cout << "[Timing]: " << what << ": " << std::to_string(std::chrono::duration_cast(t).count()) << " [sec]\n"; } } private: Tpoint start_; Tpoint stop_; }; /*! * A Logger for entire programm. */ struct Log { struct Endl {} endl; //!< a tag objec to to use it as a new line request. //! We provide logging via << operator template 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 void triangle_out (value_t s, F&& f) { f << "Total triangles: " << s << '\n'; } //! vector out result printing function template void vector_out (std::vector& 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_ */