diff --git a/Sheet7/Ex_5678/Makefile b/Sheet7/Ex_5678/Makefile new file mode 100644 index 0000000..fac14f7 --- /dev/null +++ b/Sheet7/Ex_5678/Makefile @@ -0,0 +1,23 @@ +# +# Compile with +# make 2>&1 | grep -v openmpi +# to avoid warnings caused by OpenMPI + +# use GNU-Compiler tools +COMPILER=GCC_ +# alternatively from the shell +# export COMPILER=GCC_ +# or, alternatively from the shell +# make COMPILER=GCC_ + +MAIN = main +SOURCES = ${MAIN}.cpp VecFuncs.cpp +OBJECTS = $(SOURCES:.cpp=.o) + +PROGRAM = ${MAIN}.${COMPILER} + +# uncomment the next to lines for debugging and detailed performance analysis +CXXFLAGS += -g +LINKFLAGS += + +include ../${COMPILER}default.mk diff --git a/Sheet7/Ex_5678/VecFuncs.cpp b/Sheet7/Ex_5678/VecFuncs.cpp new file mode 100644 index 0000000..3514101 --- /dev/null +++ b/Sheet7/Ex_5678/VecFuncs.cpp @@ -0,0 +1,117 @@ +#include "VecFuncs.h" +#include +#include +#include +#include + +void DebugVector(const std::vector& xin, MPI_Comm icomm) +{ + int rank, size; + MPI_Comm_rank(icomm, &rank); + MPI_Comm_size(icomm, &size); + int ierr; + + int active_rank = -1; + + for (int step = 0; step < size; ++step) + { + if (rank == 0) + { + std::cout << "Enter rank to display vector: " << std::endl; + std::cin >> active_rank; + } + + ierr = MPI_Bcast(&active_rank, 1, MPI_INT, 0, icomm); + assert(ierr == 0); + + MPI_Barrier(icomm); + + if (rank == active_rank) + { + std::cout << "Output from process " << rank << std::endl; + + for (size_t i = 0; i < xin.size(); ++i) + { + std::cout << "xin[" << i << "] = " << xin[i] << std::endl; + } + + std::cout << std::endl; + } + + MPI_Barrier(icomm); + } +} + +double par_scalar(const std::vector &x, const std::vector &y, const MPI_Comm &comm) { + assert(x.size()==y.size()); + + double local_sum = 0.0; + for (int k = 0; k < x.size(); ++k) { + local_sum += x[k] * y[k]; + } + + double global_sum = 0.0; + int mpi_error = MPI_Allreduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, comm); + assert(mpi_error == 0); + + return global_sum; +} + +void par_minmax(std::vector &x, double &min_value, double &max_value, const MPI_Comm &icomm) +{ + int myrank; + MPI_Comm_rank(icomm, &myrank); + + int local_n = x.size(); + int global_offset = myrank * local_n; + + struct {double value; int idx;} local_min, local_max, global_min, global_max; // global index + + local_min.value = local_max.value = x[0]; + local_min.idx = local_max.idx = global_offset; + + // finding local min/max with the corresponding global index + for (int i = 1; i < local_n; ++i) { + int global_idx = global_offset + i; + if (x[i] < local_min.value){ + local_min.value = x[i]; + local_min.idx = global_idx; + } + if (x[i] > local_max.value){ + local_max.value = x[i]; + local_max.idx = global_idx; + } + } + + // reduction to the global one including the global index (need it later for interchanging) + MPI_Allreduce(&local_min, &global_min, 1, MPI_DOUBLE_INT, MPI_MINLOC, icomm); + MPI_Allreduce(&local_max, &global_max, 1, MPI_DOUBLE_INT, MPI_MAXLOC, icomm); + min_value = global_min.value; + max_value = global_max.value; + + // calculating the process and the local index for interchanging the min and max value + int rank_min = global_min.idx / local_n; + int rank_max = global_max.idx / local_n; + int local_min_idx = global_min.idx % local_n; + int local_max_idx = global_max.idx % local_n; + + // interchanging + if (rank_min == rank_max){ + std::swap(x[local_min_idx], x[local_max_idx]); + } + else { + double recv_value; + if (myrank == rank_min){ + MPI_Sendrecv(&x[local_min_idx], 1, MPI_DOUBLE, rank_max, 0, &recv_value, 1, MPI_DOUBLE, rank_max, 0, icomm, MPI_STATUS_IGNORE); + x[local_min_idx] = recv_value; + } + if (myrank == rank_max){ + MPI_Sendrecv(&x[local_max_idx], 1, MPI_DOUBLE, rank_min, 0, &recv_value, 1, MPI_DOUBLE, rank_min, 0, icomm, MPI_STATUS_IGNORE); + x[local_max_idx] = recv_value; + } + + } + + + return; +} diff --git a/Sheet7/Ex_5678/VecFuncs.h b/Sheet7/Ex_5678/VecFuncs.h new file mode 100644 index 0000000..c60e17e --- /dev/null +++ b/Sheet7/Ex_5678/VecFuncs.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include +#include + +void DebugVector(const std::vector& xin, MPI_Comm icomm); + +double par_scalar(const std::vector &x, const std::vector &y, const MPI_Comm &icomm); + +void par_minmax(std::vector &x, double &min_val, double &max_val, const MPI_Comm &icomm); \ No newline at end of file diff --git a/Sheet7/Ex_5678/main.cpp b/Sheet7/Ex_5678/main.cpp new file mode 100644 index 0000000..4c3092b --- /dev/null +++ b/Sheet7/Ex_5678/main.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include "VecFuncs.h" +using namespace std; + + +int main(int argc, char** argv) +{ + MPI_Init(&argc, &argv); + MPI_Comm icomm = MPI_COMM_WORLD; + int myrank; + MPI_Comm_rank(icomm, &myrank); + + int n = 20; + vector x(n); + vector y = x; + for (int i = 0; i < n; ++i) + { + x[i] = myrank*100 + (i % 5)*10 + i; + y[i] = 1.0/(x[i]); + } + if(myrank == 0) // so scalar product is well defined (avoid division by 0) + y[0] = 0; + + //E5 + if (myrank == 0) cout << "E5" << endl; + DebugVector(x, icomm); + + //E6 + if (myrank == 0) cout << "E6" << endl; + double scalar_product = par_scalar(x, y, icomm); + + if (myrank == 0) + { + cout << " = " << scalar_product << endl << endl; + } + + // E7 + if (myrank == 0) cout << "E7" << endl; + double xmin, xmax; + par_minmax(x, xmin, xmax, icomm); + + if (myrank == 0) + { + cout << "Global min: " << xmin << endl; + cout << "Global max: " << xmax << endl << endl; + } + + // E8 + if (myrank == 0) cout << "E8" << endl; + vector x_new(n); + + // All to all + if (myrank == 0) cout << "All to all" << endl; + MPI_Alltoall(x.data(), 5, MPI_DOUBLE, x_new.data(), 5, MPI_DOUBLE, icomm); + DebugVector(x_new, icomm); + + if (myrank == 0) cout << "All to all (in place)" << endl; + MPI_Alltoall(MPI_IN_PLACE, 0, MPI_DOUBLE, x.data(), 5, MPI_DOUBLE, icomm); + + DebugVector(x, icomm); + + + MPI_Finalize(); + return 0; +}