282 lines
8.1 KiB
C++
282 lines
8.1 KiB
C++
/*!
|
|
* \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 programm.
|
|
*/
|
|
struct Log {
|
|
struct Endl {} endl; //!< a tag objec 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_ */
|