Newer
Older
// Constructor to initialize the distributed matrix
DistributedMatrix::DistributedMatrix(const Matrix& matrix, int numProcesses)
: localData(0, 0){
this->globalRows = matrix.numRows();
this->globalCols = matrix.numCols();
this->numProcesses = numProcesses;
this->rank = 0;
this->localCols = this->globalCols / this->numProcesses;
this->startCol = 0;
int remainingCols = globalCols % numProcesses;
this->startCol = rank * localCols + min(rank, remainingCols);
this->localData = Matrix(this->globalRows, this->localCols);
for (int i = 0; i < this->globalRows; ++i) {
for (int j = 0; j < this->localCols; ++j) {
this->localData.set(i, j, matrix.get(i, this->startCol + j));
DistributedMatrix::DistributedMatrix(const DistributedMatrix& other)
: localData(0, 0){
this->globalRows = other.globalRows;
this->globalCols = other.globalCols;
this->localCols = other.localCols;
this->startCol = other.startCol;
this->numProcesses = other.numProcesses;
this->rank = other.rank;
}
double DistributedMatrix::get(int i, int j) const {
if (j < startCol || j >= startCol + localCols) {
throw std::out_of_range("Attempt to access non-local column in get()");
}
void DistributedMatrix::set(int i, int j, double value) {
if (j < startCol || j >= startCol + localCols) {
throw std::out_of_range("Attempt to access non-local column in set()");
int DistributedMatrix::globalColIndex(int localColIndex) const {
return startCol + localColIndex;
}
int DistributedMatrix::localColIndex(int globalColIndex) const {
if (globalColIndex >= startCol && globalColIndex < startCol + localCols) {
return globalColIndex - startCol;
}
}
int DistributedMatrix::ownerProcess(int globalColIndex) const {
int remainingCols = globalCols % numProcesses;
for (int p = 0; p < numProcesses; ++p) {
int start = p * localCols + min(p, remainingCols);
int cols = localCols + (p < remainingCols ? 1 : 0);
if (globalColIndex >= start && globalColIndex < start + cols) {
return p;
}
}
const Matrix& DistributedMatrix::getLocalData() const {
return localData;
}
Matrix DistributedMatrix::gather() const {
vector<double> localBuffer(localCols * globalRows);
for (int i = 0; i < globalRows; ++i) {
for (int j = 0; j < localCols; ++j) {
localBuffer[i * localCols + j] = localData.get(i, j);
}
}
vector<int> counts(numProcesses);
vector<int> displacements(numProcesses);
int remainingCols = globalCols % numProcesses;
for (int p = 0; p < numProcesses; ++p) {
int p_cols = (globalCols / numProcesses) + (p < remainingCols ? 1 : 0);
counts[p] = globalRows * p_cols;
displacements[p] = (p == 0) ? 0 : displacements[p - 1] + counts[p - 1];
}
vector<double> buffer(globalRows * globalCols);
MPI_Allgatherv(
localBuffer.data(),
localCols * globalRows,
MPI_DOUBLE,
buffer.data(),
counts.data(),
displacements.data(),
MPI_DOUBLE,
MPI_COMM_WORLD
);
Matrix fullMatrix(globalRows, globalCols);
int currentCol = 0;
for (int p = 0; p < numProcesses; ++p) {
int cols = (globalCols/numProcesses) + (p < remainingCols ? 1 : 0);
for (int j = 0; j < cols; ++j) {
for (int i = 0; i < globalRows; ++i) {
double val = buffer[displacements[p] + j + i * cols];
fullMatrix.set(i, currentCol, val);
DistributedMatrix DistributedMatrix::apply(const std::function<double(double)> &func) const {
for (int i = 0; i < localData.numRows(); ++i) {
for (int j = 0; j < localData.numCols(); ++j) {
double value = localData.get(i, j);
result.localData.set(i, j, func(value));
DistributedMatrix DistributedMatrix::applyBinary(
const DistributedMatrix& a,
const DistributedMatrix& b,
const std::function<double(double, double)>& func) {
DistributedMatrix result(a);
for (int i = 0; i < a.localData.numRows(); ++i) {
for (int j = 0; j < a.localData.numCols(); ++j) {
double valA = a.localData.get(i, j);
double valB = b.localData.get(i, j);
result.localData.set(i, j, func(valA, valB));
}
}
return result;
}
double DistributedMatrix::sum() const {
double localSum = 0.0;
for (int i = 0; i < globalRows; ++i) {
for (int j = 0; j < localCols; ++j) {
localSum += localData.get(i, j);
}
}
double globalSum = 0.0;
MPI_Allreduce(&localSum, &globalSum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
DistributedMatrix multiply(const Matrix& left, const DistributedMatrix& right) {
int globalRows = left.numRows();
int globalCols = right.numCols();
int localCols = right.localCols;
Matrix resultMatrix(globalRows, globalCols);
DistributedMatrix result(resultMatrix, right.numProcesses);
for (int i = 0; i < globalRows; ++i) {
for (int j = 0; j < localCols; ++j) {
double sum = 0.0;
for (int k = 0; k < left.numCols(); ++k) {
sum += left.get(i, k) * right.localData.get(k, j);
}
result.localData.set(i, j, sum);
}
}
return result;
}
Matrix DistributedMatrix::multiplyTransposed(const DistributedMatrix &other) const {
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
Matrix result = (*this).localData * other.getLocalData().transpose();
int localSize = result.numRows() * result.numCols();
std::vector<int> counts(numProcesses);
std::vector<int> displacements(numProcesses);
MPI_Allgather(&localSize, 1, MPI_INT, counts.data(), 1, MPI_INT, MPI_COMM_WORLD);
displacements[0] = 0;
for (int i = 1; i < numProcesses; ++i)
displacements[i] = displacements[i - 1] + counts[i - 1];
std::vector<double> buffer(this->globalRows * other.globalRows);
MPI_Allreduce(
result.getData().data(),
buffer.data(),
globalRows * other.globalRows,
MPI_DOUBLE,
MPI_SUM,
MPI_COMM_WORLD
);
Matrix fullMatrix(globalRows, other.globalRows);
for (int i = 0; i < globalRows; ++i) {
for (int j = 0; j < other.globalRows; ++j) {
fullMatrix.set(i, j, buffer[i * other.globalRows + j]);