#include <mpi.h>
#include <iostream>
#include <vector>
#include <algorithm>
int N = 400; // Size of the matrices (e.g., 100x100)
void printMatrix(const std::vector<std::vector<int>>& matrix, int rows, int cols) {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
std::cout << matrix[i][j] << " ";
}
std::cout << std::endl;
}
}
int main(int argc, char** argv) {
MPI_Init(&argc, &argv);
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
// Define matrices
std::vector<std::vector<int>> matrix1(N, std::vector<int>(N, 1)); // Initialize with 1s for simplicity
std::vector<std::vector<int>> matrix2(N, std::vector<int>(N, 1)); // Initialize with 1s for simplicity
std::vector<std::vector<int>> resultMatrix(N, std::vector<int>(N, 0));
if (rank == 0) {
std::cout << "Starting matrix multiplication for " << N << "x" << N << " matrices using point-to-point communication..." << std::endl;
}
// Start timer after data distribution
double start_time = MPI_Wtime();
// Broadcast matrix2 to all processes (all processes need matrix2 for computation)
for (int i = 0; i < N; ++i) {
MPI_Bcast(matrix2[i].data(), N, MPI_INT, 0, MPI_COMM_WORLD);
}
// Calculate rows_per_process and start index for each process
int rows_per_process = N / size;
int extra_rows = N % size; // To handle cases where N is not evenly divisible by size
// Assign extra row to processes if N % size != 0
int start_row = rank * rows_per_process + std::min(rank, extra_rows);
int end_row = start_row + rows_per_process + (rank < extra_rows ? 1 : 0);
// Each process calculates its assigned rows
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < N; ++j) {
resultMatrix[i][j] = 0;
for (int k = 0; k < N; ++k) {
resultMatrix[i][j] += matrix1[i][k] * matrix2[k][j];
}
}
}
// Send the computed rows back to the root process (rank 0)
if (rank == 0) {
// Root process gathers its own rows
for (int i = 1; i < size; ++i) {
int start = i * rows_per_process + std::min(i, extra_rows);
int end = start + rows_per_process + (i < extra_rows ? 1 : 0);
for (int j = start; j < end; ++j) {
MPI_Recv(resultMatrix[j].data(), N, MPI_INT, i, j, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
}
}
else {
// Non-root processes send their computed rows to root
for (int i = start_row; i < end_row; ++i) {
MPI_Send(resultMatrix[i].data(), N, MPI_INT, 0, i, MPI_COMM_WORLD);
}
}
// End timer
double end_time = MPI_Wtime();
// Print the result and elapsed time in the root process
if (rank == 0) {
printMatrix(matrix1, N, N);
printMatrix(matrix2, N, N);
printMatrix(resultMatrix,N,N);
std::cout << "Matrix multiplication complete." << std::endl;
std::cout << "Time taken: " << end_time - start_time << " seconds" << std::endl;
}
MPI_Finalize();
return 0;
}
I2luY2x1ZGUgPG1waS5oPgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDx2ZWN0b3I+CiNpbmNsdWRlIDxhbGdvcml0aG0+CgogaW50IE4gPSA0MDA7IC8vIFNpemUgb2YgdGhlIG1hdHJpY2VzIChlLmcuLCAxMDB4MTAwKQoKdm9pZCBwcmludE1hdHJpeChjb25zdCBzdGQ6OnZlY3RvcjxzdGQ6OnZlY3RvcjxpbnQ+PiYgbWF0cml4LCBpbnQgcm93cywgaW50IGNvbHMpIHsKCWZvciAoaW50IGkgPSAwOyBpIDwgcm93czsgKytpKSB7CgkJZm9yIChpbnQgaiA9IDA7IGogPCBjb2xzOyArK2opIHsKCQkJc3RkOjpjb3V0IDw8IG1hdHJpeFtpXVtqXSA8PCAiICI7CgkJfQoJCXN0ZDo6Y291dCA8PCBzdGQ6OmVuZGw7Cgl9Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyKiogYXJndikgewoJTVBJX0luaXQoJmFyZ2MsICZhcmd2KTsKCWludCByYW5rLCBzaXplOwoJTVBJX0NvbW1fcmFuayhNUElfQ09NTV9XT1JMRCwgJnJhbmspOwoJTVBJX0NvbW1fc2l6ZShNUElfQ09NTV9XT1JMRCwgJnNpemUpOwoKCS8vIERlZmluZSBtYXRyaWNlcwoJc3RkOjp2ZWN0b3I8c3RkOjp2ZWN0b3I8aW50Pj4gbWF0cml4MShOLCBzdGQ6OnZlY3RvcjxpbnQ+KE4sIDEpKTsgLy8gSW5pdGlhbGl6ZSB3aXRoIDFzIGZvciBzaW1wbGljaXR5CglzdGQ6OnZlY3RvcjxzdGQ6OnZlY3RvcjxpbnQ+PiBtYXRyaXgyKE4sIHN0ZDo6dmVjdG9yPGludD4oTiwgMSkpOyAvLyBJbml0aWFsaXplIHdpdGggMXMgZm9yIHNpbXBsaWNpdHkKCXN0ZDo6dmVjdG9yPHN0ZDo6dmVjdG9yPGludD4+IHJlc3VsdE1hdHJpeChOLCBzdGQ6OnZlY3RvcjxpbnQ+KE4sIDApKTsKCglpZiAocmFuayA9PSAwKSB7CgkJc3RkOjpjb3V0IDw8ICJTdGFydGluZyBtYXRyaXggbXVsdGlwbGljYXRpb24gZm9yICIgPDwgTiA8PCAieCIgPDwgTiA8PCAiIG1hdHJpY2VzIHVzaW5nIHBvaW50LXRvLXBvaW50IGNvbW11bmljYXRpb24uLi4iIDw8IHN0ZDo6ZW5kbDsKCX0KCgkvLyBTdGFydCB0aW1lciBhZnRlciBkYXRhIGRpc3RyaWJ1dGlvbgoJZG91YmxlIHN0YXJ0X3RpbWUgPSBNUElfV3RpbWUoKTsKCgkvLyBCcm9hZGNhc3QgbWF0cml4MiB0byBhbGwgcHJvY2Vzc2VzIChhbGwgcHJvY2Vzc2VzIG5lZWQgbWF0cml4MiBmb3IgY29tcHV0YXRpb24pCglmb3IgKGludCBpID0gMDsgaSA8IE47ICsraSkgewoJCU1QSV9CY2FzdChtYXRyaXgyW2ldLmRhdGEoKSwgTiwgTVBJX0lOVCwgMCwgTVBJX0NPTU1fV09STEQpOwoJfQoKCS8vIENhbGN1bGF0ZSByb3dzX3Blcl9wcm9jZXNzIGFuZCBzdGFydCBpbmRleCBmb3IgZWFjaCBwcm9jZXNzCglpbnQgcm93c19wZXJfcHJvY2VzcyA9IE4gLyBzaXplOwoJaW50IGV4dHJhX3Jvd3MgPSBOICUgc2l6ZTsgLy8gVG8gaGFuZGxlIGNhc2VzIHdoZXJlIE4gaXMgbm90IGV2ZW5seSBkaXZpc2libGUgYnkgc2l6ZQoKCQkJCQkJCSAgIC8vIEFzc2lnbiBleHRyYSByb3cgdG8gcHJvY2Vzc2VzIGlmIE4gJSBzaXplICE9IDAKCWludCBzdGFydF9yb3cgPSByYW5rICogcm93c19wZXJfcHJvY2VzcyArIHN0ZDo6bWluKHJhbmssIGV4dHJhX3Jvd3MpOwoJaW50IGVuZF9yb3cgPSBzdGFydF9yb3cgKyByb3dzX3Blcl9wcm9jZXNzICsgKHJhbmsgPCBleHRyYV9yb3dzID8gMSA6IDApOwoKCS8vIEVhY2ggcHJvY2VzcyBjYWxjdWxhdGVzIGl0cyBhc3NpZ25lZCByb3dzCglmb3IgKGludCBpID0gc3RhcnRfcm93OyBpIDwgZW5kX3JvdzsgKytpKSB7CgkJZm9yIChpbnQgaiA9IDA7IGogPCBOOyArK2opIHsKCQkJcmVzdWx0TWF0cml4W2ldW2pdID0gMDsKCQkJZm9yIChpbnQgayA9IDA7IGsgPCBOOyArK2spIHsKCQkJCXJlc3VsdE1hdHJpeFtpXVtqXSArPSBtYXRyaXgxW2ldW2tdICogbWF0cml4MltrXVtqXTsKCQkJfQoJCX0KCX0KCgkvLyBTZW5kIHRoZSBjb21wdXRlZCByb3dzIGJhY2sgdG8gdGhlIHJvb3QgcHJvY2VzcyAocmFuayAwKQoJaWYgKHJhbmsgPT0gMCkgewoJCS8vIFJvb3QgcHJvY2VzcyBnYXRoZXJzIGl0cyBvd24gcm93cwoJCWZvciAoaW50IGkgPSAxOyBpIDwgc2l6ZTsgKytpKSB7CgkJCWludCBzdGFydCA9IGkgKiByb3dzX3Blcl9wcm9jZXNzICsgc3RkOjptaW4oaSwgZXh0cmFfcm93cyk7CgkJCWludCBlbmQgPSBzdGFydCArIHJvd3NfcGVyX3Byb2Nlc3MgKyAoaSA8IGV4dHJhX3Jvd3MgPyAxIDogMCk7CgoJCQlmb3IgKGludCBqID0gc3RhcnQ7IGogPCBlbmQ7ICsraikgewoJCQkJTVBJX1JlY3YocmVzdWx0TWF0cml4W2pdLmRhdGEoKSwgTiwgTVBJX0lOVCwgaSwgaiwgTVBJX0NPTU1fV09STEQsIE1QSV9TVEFUVVNfSUdOT1JFKTsKCQkJfQoJCX0KCX0KCWVsc2UgewoJCS8vIE5vbi1yb290IHByb2Nlc3NlcyBzZW5kIHRoZWlyIGNvbXB1dGVkIHJvd3MgdG8gcm9vdAoJCWZvciAoaW50IGkgPSBzdGFydF9yb3c7IGkgPCBlbmRfcm93OyArK2kpIHsKCQkJTVBJX1NlbmQocmVzdWx0TWF0cml4W2ldLmRhdGEoKSwgTiwgTVBJX0lOVCwgMCwgaSwgTVBJX0NPTU1fV09STEQpOwoJCX0KCX0KCgkvLyBFbmQgdGltZXIKCWRvdWJsZSBlbmRfdGltZSA9IE1QSV9XdGltZSgpOwoKCS8vIFByaW50IHRoZSByZXN1bHQgYW5kIGVsYXBzZWQgdGltZSBpbiB0aGUgcm9vdCBwcm9jZXNzCglpZiAocmFuayA9PSAwKSB7CgkJCgoJCXByaW50TWF0cml4KG1hdHJpeDEsIE4sIE4pOwoJCXByaW50TWF0cml4KG1hdHJpeDIsIE4sIE4pOwoJCXByaW50TWF0cml4KHJlc3VsdE1hdHJpeCxOLE4pOwoKCQlzdGQ6OmNvdXQgPDwgIk1hdHJpeCBtdWx0aXBsaWNhdGlvbiBjb21wbGV0ZS4iIDw8IHN0ZDo6ZW5kbDsKCQlzdGQ6OmNvdXQgPDwgIlRpbWUgdGFrZW46ICIgPDwgZW5kX3RpbWUgLSBzdGFydF90aW1lIDw8ICIgc2Vjb25kcyIgPDwgc3RkOjplbmRsOwoJfQoKCU1QSV9GaW5hbGl6ZSgpOwoJcmV0dXJuIDA7Cn0K