#include "ParSparseMatrix.h"
#include <fstream>
#ifdef TIMING_ON
double time_diff(timespec &start, timespec &end)
{
return (double)(1e9 * (end.tv_sec - start.tv_sec) +
end.tv_nsec - start.tv_nsec) / 1e9;
}
#endif
using namespace MPI_Wrappers;
using namespace std;
namespace ATC_matrix {
ParSparseMatrix<double>::ParSparseMatrix(MPI_Comm comm, INDEX rows, INDEX cols)
: SparseMatrix<double>(rows, cols), _comm(comm) {}
ParSparseMatrix<double>::ParSparseMatrix(MPI_Comm comm,
const SparseMatrix<double> &c) :
SparseMatrix<double>(c), _comm(comm) {}
ParSparseMatrix<double>::ParSparseMatrix(MPI_Comm comm,
INDEX* rows, INDEX* cols, double* vals, INDEX size,
INDEX nRows, INDEX nCols, INDEX nRowsCRS)
: SparseMatrix<double>(rows, cols, vals, size, nRows,
nCols, nRowsCRS), _comm(comm) {}
void ParSparseMatrix<double>::MultMv(const Vector<double>& v,
DenseVector<double>& c) const
{
int numProcs = MPI_Wrappers::size(_comm);
#ifdef DISABLE_PAR_HEURISTICS
if (numProcs == 1 || _size < 300) {
#else
if ( numProcs == 1 ||
(_size < 50000 || _size > 10000000) ||
((_size < 150000 || _size > 5000000) && numProcs > 8) ||
((_size < 500000 || _size > 2500000) && numProcs > 16 ) ||
(numProcs > 32)) {
#endif
SparseMatrix<double>::MultMv(v, c);
return;
}
SparseMatrix<double>::compress(*this);
GCK(*this, v, this->nCols() != v.size(), "ParSparseMatrix * Vector")
SparseMatrix<double> A_local;
partition(*static_cast<ParSparseMatrix<double>*>(&A_local));
#ifdef TIMING_ON
timespec before, after;
clock_gettime(CLOCK_MONOTONIC, &before);
#endif
DenseVector<double> c_local = A_local * v;
#ifdef TIMING_ON
clock_gettime(CLOCK_MONOTONIC, &after);
cout << "P" << MPI_Wrappers::rank(MPI_COMM_WORLD) << " " << time_diff(before,after) << " mat.vec time\n";
barrier(MPI_COMM_WORLD);
#endif
static_cast<ParSparseMatrix<double>*>(&A_local)->finalize();
#ifdef TIMING_ON
barrier(MPI_COMM_WORLD);
clock_gettime(CLOCK_MONOTONIC, &before);
#endif
allsum(_comm, c_local.ptr(), c.ptr(), c_local.size());
#ifdef TIMING_ON
clock_gettime(CLOCK_MONOTONIC, &after);
cout << "P" << MPI_Wrappers::rank(MPI_COMM_WORLD) << " " << time_diff(before,after) << " allsum time\n";
#endif
}
DenseVector<double> ParSparseMatrix<double>::transMat(
const Vector<double>& v) const {
SparseMatrix<double>::compress(*this);
GCK(*this, v, this->nRows() != v.size(), "ParSparseMatrix transpose * Vector")
DenseVector<double> c(nCols(), true);
SparseMatrix<double> A_local;
partition(*static_cast<ParSparseMatrix<double>*>(&A_local));
DenseVector<double> c_local = A_local.transMat(v);
static_cast<ParSparseMatrix<double>*>(&A_local)->finalize();
allsum(_comm, c_local.ptr(), c.ptr(), c_local.size());
return c;
}
void ParSparseMatrix<double>::MultAB(const Matrix<double>& B,
DenseMatrix<double>& C) const {
SparseMatrix<double>::compress(*this);
GCK(*this, B, this->nCols() != B.nRows(), "ParSparseMatrix * Matrix")
SparseMatrix<double> A_local;
partition(*static_cast<ParSparseMatrix<double>*>(&A_local));
#ifdef TIMING_ON
timespec before, after;
barrier(MPI_COMM_WORLD);
clock_gettime(CLOCK_MONOTONIC, &before);
#endif
DenseMatrix<double> C_local = A_local * B;
#ifdef TIMING_ON
barrier(MPI_COMM_WORLD);
clock_gettime(CLOCK_MONOTONIC, &after);
cout << "P" << MPI_Wrappers::rank(MPI_COMM_WORLD) << " " << time_diff(after,before) << " mat.vec time\n";
#endif
static_cast<ParSparseMatrix<double>*>(&A_local)->finalize();
#ifdef TIMING_ON
barrier(MPI_COMM_WORLD);
clock_gettime(CLOCK_MONOTONIC, &before);
#endif
allsum(_comm, C_local.ptr(), C.ptr(), C_local.size());
#ifdef TIMING_ON
barrier(MPI_COMM_WORLD);
clock_gettime(CLOCK_MONOTONIC, &after);
cout << "P" << MPI_Wrappers::rank(MPI_COMM_WORLD) << " " << time_diff(after,before) << " allsum time\n";
#endif
}
DenseMatrix<double> ParSparseMatrix<double>::transMat(
const DenseMatrix<double>& B) const {
SparseMatrix<double>::compress(*this);
GCK(*this, B, this->nRows() != B.nRows(), "ParSparseMatrix transpose * Matrix")
DenseMatrix<double> C(nCols(), B.nCols(), true);
SparseMatrix<double> A_local;
partition(*static_cast<ParSparseMatrix<double>*>(&A_local));
DenseMatrix<double> C_local = A_local.transMat(B);
static_cast<ParSparseMatrix<double>*>(&A_local)->finalize();
allsum(_comm, C_local.ptr(), C.ptr(), C_local.size());
return C;
}
DenseMatrix<double> ParSparseMatrix<double>::transMat(
const SparseMatrix<double>& B) const {
SparseMatrix<double>::compress(*this);
GCK(*this, B, this->nRows() != B.nRows(), "ParSparseMatrix transpose * SparseMatrix")
DenseMatrix<double> C(nCols(), B.nCols(), true);
SparseMatrix<double> A_local;
partition(*static_cast<ParSparseMatrix<double>*>(&A_local));
DenseMatrix<double> C_local = A_local.transMat(B);
static_cast<ParSparseMatrix<double>*>(&A_local)->finalize();
allsum(_comm, C_local.ptr(), C.ptr(), C_local.size());
return C;
}
void ParSparseMatrix<double>::partition(
ParSparseMatrix<double>& A_local) const {
INDEX startIndex = (MPI_Wrappers::rank(_comm) * size()) / MPI_Wrappers::size(_comm);
INDEX endIndex = ((MPI_Wrappers::rank(_comm) + 1) * size()) / MPI_Wrappers::size(_comm);
A_local._nRows = _nRows;
A_local._nCols = _nCols;
A_local._size = endIndex - startIndex;
A_local._nRowsCRS = _nRowsCRS;
A_local._val = _val + startIndex;
A_local._ja = _ja + startIndex;
A_local._ia = new INDEX[nRowsCRS() + 1];
INDEX numRows = nRowsCRS();
if (A_local._size > 0) {
for (INDEX i = 0; i < numRows + 1; i++) {
A_local._ia[i] = std::min(std::max((_ia[i] - startIndex), 0),
endIndex - startIndex);
}
} else {
A_local._nRowsCRS = 0;
}
}
void ParSparseMatrix<double>::finalize() {
_val = NULL;
_ja = NULL;
}
void ParSparseMatrix<double>::operator=(const SparseMatrix<double> &source)
{
copy(source);
}
}