MPI scatterv gatherv - c++

In the (semplified) code below, I have a class whose first member is a pointer to pointers (a dynamic matrix), I want to know how to use scatterv and gatherv. My target is to split the matrix "horizontally" using the pointers to the rows.
class:
#include <iostream>
using namespace std;
class Mat{
private:
int **m;
unsigned cols;
unsigned rows;
void allocate_mem(int ***ptr, unsigned r, unsigned c){
*ptr = new int *[r];
(*ptr)[0] = new int[r*c];
for(unsigned i = 1; i < r; i++)
(*ptr)[i] = (*ptr)[0] + i*c;
}
public:
Mat(){
rows = 1;
cols = 1;
allocate_mem(&m, 1, 1);
m[0][0] = 0;
}
Mat(unsigned n_rows, unsigned n_cols){
rows = n_rows;
cols = n_cols;
allocate_mem(&m, rows, cols);
for(unsigned i = 0; i < rows; i++)
for(unsigned j = 0; j < cols; j++)
m[i][j] = i+j;
}
Mat &operator=(const Mat &mrx){
int **new_ptr = NULL;
allocate_mem(&new_ptr, mrx.rows, mrx.cols);
for(unsigned i = 0; i < mrx.rows; i++)
for(unsigned j = 0; j < mrx.cols; j++)
new_ptr[i][j] = mrx[i][j];
delete[] m[0];
delete[] m;
m = new_ptr;
rows = mrx.rows;
cols = mrx.cols;
return *this;
}
const int *operator[](unsigned n) const{
return m[n];
}
void create_output(){
for(unsigned i = 0; i < cols; i++){
for(unsigned j = 0; j < rows; j++){
cout << m[i][j] << "\t";
}
cout << "\n";
}
}
~Mat(){
delete[] m[0];
delete[] m;
}
};
main:
#include "Mat.cpp"
#include <mpi.h>
#include <iostream>
using namespace std;
int main(int argc, char **argv){
MPI_Init(&argc, &argv);
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int p;
MPI_Comm_size(MPI_COMM_WORLD, &p);
Mat m;
if(rank==0){
m = Mat(10,10);
cout << "First:" << endl;
m.create_output();
}
MPI_Barrier(MPI_COMM_WORLD);
//MPI_Scatterv();
//MPI_Gatherv();
if(rank==0){
cout << "Second:" << endl;
m.create_output();
}
MPI_Finalize();
return 0;
}

Related

I am not sure why this vector transpose is not working

I want to tranpose a matrix using vector?
//I am trying to 'tranpose' a vector matrix, but it's not running
#include <iostream>
#include <vector>
using namespace std;
// this will tranpose matrix
int transpose(vector<vector<int>> &arr){
int n = arr.size();
int m = arr[0].size();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}}}
// this will swap the matrix
int swap_vector(vector<vector<int>> &arr){
int n = arr.size();
int m = arr[0].size();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m/2; j++) {
int temp = arr[i][j];
arr[i][j] = arr[i][j-1-i];
arr[i][j-1-i] = temp;
}}}
vector<vector<int>> arrh{{1,2,3,4},{5,6,7,8},
{9,10,11,12},
{13,14,15,16} };
int main() {
transpose(arrh);
swap_vector(arrh);
for (int i=0; i<arrh.size(); i++) {
for (int j=0; j<arrh[0].size(); j++) {
cout << arrh[i][j] << " ";}
cout << std::endl;}
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
// this will tranpose matrix
int transpose(vector<vector<int>> &arr){
int n = arr.size();
int m = arr[0].size();
for (int i = 0; i < n; i++) {
for (int j = i; j < m; j++) {
int temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
// this will swap the matrix
int swap_vector(vector<vector<int>> &arr){
int n = arr.size();
int m = arr[0].size();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m/2; j++) {
int temp = arr[i][j];
arr[i][j] = arr[i][m-1-j];
arr[i][m-1-j] = temp;
}
}
}
vector<vector<int>> arrh{{1,2,3,4},{5,6,7,8},
{9,10,11,12},
{13,14,15,16} };
int main() {
transpose(arrh);
swap_vector(arrh);
for (int i=0; i<arrh.size(); i++) {
for (int j=0; j<arrh[0].size(); j++) {
cout << arrh[i][j] << " ";
}
cout << std::endl;
}
return 0;
}

Sorting a list with indexes of another

I am trying to sort a list of indexes based on a list of string, and I receive bellow error - Segmentation fault. I cannot understand why I receive this error and how to solve it?
#include <iostream>
#include <string.h>
using namespace std;
int main() {
int size = 5;
char* mass[size];
int num[size];
for(int i = 0; i < size; i++) {
mass[i] = new char[20];
num[i] = i;
cin >> mass[i];
}
for(int i = 0; i < size; i++){
for(int j = size; j > i; j--)
if(strcmp(mass[num[j-1]], mass[num[j]]) > 0){
int tmp = num[j-1];
num[j-1] = num[j];
num[j] = tmp;
}
}
for(int i = 0; i < size; i++){
cout << mass[num[i]] << ", ";
}
return 0;
}
In the inner loop you start with j = size and then num[j] is an out-of-bounds array access.
In modern C++ you would solve this like this:
#include <iostream>
#include <array>
#include <algorithm>
int main() {
const int size = 5;
std::array<std::string, size> mass;
std::array<int, size> num;
for (int i = 0; i < size; i++) {
std::cin >> mass[i];
num[i] = i;
}
std::ranges::sort(num, [mass](int a, int b) { return mass[a] <= mass[b];});
for(int i = 0; i < size; i++){
std::cout << mass[num[i]] << ", ";
}
std::cout << std::endl;
return 0;
}

MPI_Scatter and MPI_Allgather

Okay, so here is another question related to my previous post MPI_Broadcast using vectors
I want to scatter a matrix (4x4) in such a way that each process receives one row (total of 4 processes). I am using vectors which need to be resized and a bit of playing around. It worked well when using arrays but with vectors I can't get the desired output.
updated code (Minimal)
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cmath>
#include <chrono>
#include <cmath>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include"mpi.h"
using namespace std;
const int num_rows1 = 4, num_rows2 = 4, num_cols1 = 4, num_cols2 = 4;
const int root = 0;
int i, j, k;
vector<vector<int> > matrix1(num_rows1, vector <int>(num_cols1));
vector<vector<int> > matrix2(num_rows2, vector <int>(num_cols2));
vector<vector<int> > result(num_rows1, vector <int>(num_cols1));
int finale[num_rows1][num_cols2];
vector<vector<int> > transpose_mat(num_cols2, vector <int>(num_rows2));
vector<int> column1(num_rows1);
vector<int> column2(num_cols2);
double start_time, end_time;
int * column3 = new int[];
//Function working with the multiplication
vector<int> mult(vector<vector<int> > A, vector<int> B)
{
//Multiplication
for (int i = 0; i < num_rows1; ++i)
{
int sum = 0;
for (int j = 0; j < num_cols1; ++j)
{
sum += A[i][j] * B[j];
}
column1.push_back(sum);
}
return column1;
}
//Function generating random matrices
vector<vector<int>> generate_matrix(int nrow, int ncol)
{
vector<vector<int>> matrix(nrow, vector <int>(ncol));
for (int i = 0; i < nrow; ++i)
{
for (int j = 0; j < ncol; ++j)
{
matrix[i][j] = (15 *rand() / RAND_MAX - 3);
}
}
return matrix;
}
//function taking the transpose
vector<vector<int>>transpose(vector<vector<int> > matrix , int nrow, int ncol)
{
//Transpose of matrix 2
for (i = 0; i < nrow; ++i)
for (j = 0; j < ncol; ++j)
{
transpose_mat[j][i] = matrix2[i][j];
}
cout << "Transpose " << endl;
for (int i = 0; i < num_rows2; ++i)
{
for (int j = 0; j < num_cols2; ++j)
{
cout << transpose_mat[i][j] << " ";
}
cout << endl;
}
return transpose_mat;
}
//main function
int main(int argc, char *argv[])
{
MPI_Status status;
MPI_Request request;
int tag = 1;
int rank;
int world_size; //Number of processes
// Initialize the MPI environment
MPI_Init(NULL, NULL);
// Get the rank of the process
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Get the name of the processor
char processor_name[MPI_MAX_PROCESSOR_NAME];
int name_len;
MPI_Get_processor_name(processor_name, &name_len);
// Get the number of processes
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
if (rank == root)
{
//Filling
matrix1 = generate_matrix(num_rows1, num_cols1);
for (int i = 0; i < num_rows1; ++i)
{
MPI_Bcast(&matrix1[i][0], num_rows1, MPI_INT, root, MPI_COMM_WORLD);
}
}
else if (rank == 1)
{
srand(time(NULL));
//Filling
matrix2 = generate_matrix(num_rows2, num_cols2);
transpose_mat = transpose(matrix2, num_rows2, num_cols2);
}
if (rank > root)
{
int size = matrix1.size();
result.resize(size);
for (int i = 0; i < size; i++){
result[i].resize(size);
}
for (int i = 0; i < size; ++i)
{
MPI_Bcast(&result[i][0], size, MPI_INT, root, MPI_COMM_WORLD);
}
}
int size1 = transpose_mat.size();
column2.resize(size1);
//Scattering the transposed matrix
for (j = 0; j < num_rows2; ++j)
{
MPI_Scatter(&transpose_mat[0][j], size1*size1 / world_size, MPI_INT, &column2[j], size1*size1 / world_size, MPI_INT, 1, MPI_COMM_WORLD);
}
cout << "The scattered data at process " << rank << " is: " << endl;
for (int j = 0; j < num_cols2; ++j)
{
cout << column2[j] << endl;
}
MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();
return 0;
}
In the updated PNG one can see that the first two rows of the matrix are scattered. The first one being received by Process 0 and the second row by Process 2. Why do Process 1 and Process 3 don't give the desired reault.
Updated PNG

C++ contiguous memory operation

I have c++ program in which I am calculating determinant of a matrix using normal array which is as follows:
/* rand example: guess the number */
#include <stdio.h> /* printf, scanf, puts, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
int** generateStandardMatrix(int dimension);
void ijMinor(int *matrix[], int *minorMatrix[], int size, int row, int column);
int determinant(int *matrix[], int size);
void ijMinor(int *matrix[], int *minorMatrix[], int size, int row, int column) {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (i < row) {
if (j < column)minorMatrix[i][j] = matrix[i][j];
else if (j == column)continue;
else minorMatrix[i][j - 1] = matrix[i][j];
}
else if (i == row)continue;
else {
if (j < column)minorMatrix[i - 1][j] = matrix[i][j];
else if (j == column)continue;
else minorMatrix[i - 1][j - 1] = matrix[i][j];
}
}
}
}
int determinant(int *matrix[], int size) {
if (size == 1)return matrix[0][0];
else {
int result = 0, sign = -1;
for (int j = 0; j < size; j++) {
int **minorMatrix;
minorMatrix = new int*[size - 1];
for (int k = 0 ; k < size - 1 ; k++)
minorMatrix[k] = new int[size - 1];
ijMinor(matrix, minorMatrix, size, 0, j);
sign *= -1;
result += sign * matrix[0][j] * determinant(minorMatrix, size - 1);
for (int i = 0; i < size - 1; i++) {
delete minorMatrix[i];
}
}
return result;
}
}
int main (int argc, char* argv[])
{
/* initialize random seed: */
srand (time(NULL));
// int iSecret, iGuess;
int dimension = atoi(argv[1]);
int rowCount = dimension , colCount = dimension;
//2d array storing the integer values
int** ary = new int*[dimension];
//vector of vector storing the indices across the array for the threads to pick up from
vector<vector<int> > vec;
ary = generateStandardMatrix(dimension);
printf("Array value : %d\n", ary[0][0]);
int detVal = determinant(ary, dimension);
printf("determinant value : %d\n", detVal);
return 0;
}
int** generateStandardMatrix(int dimension) {
int** ary = new int*[dimension];
int counter = 0;
for (int i = 0; i < dimension; ++i) {
ary[i] = new int[dimension];
counter = counter + 1;
for (int j = 0; j < dimension; ++j)
{
ary[i][j] = counter;
std::cout << ary[i][j] << "\t" << std::flush;
}
std::cout << std::endl;
}
return ary;
}
I want to replace it with code in which I allocate memory for the array before the start of the algorithm and then change the determinant and the ijMonor functions so that they don't create new array's but use the same array only.
The determinant will take parameter like: determinant(int *matrix, int *startOfMyWorkspace, int size) so that it knows where to start.
I am not good at c++ and so far I was not able to do it.
Can someone please provide some sample code.
I allocated some memory for array and created and array but was unable to change the ijMinor and determinant functions for that.
This is how I am allocating memory:
int main (int argc, char* argv[])
{
/* initialize random seed: */
srand (time(NULL));
// int iSecret, iGuess;
int dimension = atoi(argv[1]);
int *a;
size_t const N_BYTES = dimension * dimension * sizeof(int);
a = (int*)malloc(N_BYTES);
createData(dimension,a);
return 0;
}
void createData(int const dimension, int* const a)
{
int row, col;
srand((unsigned)time(NULL));
int counter;
for(int row = 0; row < dimension; row++) {
counter = counter + 1;
for(int col = 0; col < dimension; col++) {
int i = col + row * dimension;
a[i] = counter;
std::cout << a[i] << "\t" << std::flush;
}
std::cout << std::endl;
}
}
Try this.
Note if you use new to allocate an array, you need to use delete[] to free all of it. You'll get away with delete (i.e. it won't crash) but this will only free the first element. Your other functions are the same as you posted.
You're dynamically allocating space for minorMatrix in determinant function, but it's hard to see how that could be preallocated. I've modified determinant function to use allocate_arr and deallocate_arr.
int ** allocate_arr(int dimension)
{
int** a = new int*[dimension];
for (int i = 0; i < dimension; ++i)
a[i] = new int[dimension];
return a;
}
void deallocate_arr(int dimension, int **a)
{
for (int i = 0; i < dimension; ++i)
delete[] a[i];
delete[] a;
}
int determinant(int *matrix[], int size) {
if (size == 1)return matrix[0][0];
else {
int result = 0, sign = -1;
for (int j = 0; j < size; j++) {
int **minorMatrix = allocate_arr(size - 1);
ijMinor(matrix, minorMatrix, size, 0, j);
sign *= -1;
result += sign * matrix[0][j] * determinant(minorMatrix, size - 1);
deallocate_arr(size - 1, minorMatrix);
}
return result;
}
}
void generateStandardMatrix(int dimension, int**ary) {
int counter = 0;
for (int i = 0; i < dimension; ++i) {
counter = counter + 1;
for (int j = 0; j < dimension; ++j)
{
ary[i][j] = counter;
std::cout << ary[i][j] << "\t" << std::flush;
}
std::cout << std::endl;
}
}
int main(int argc, char* argv[])
{
srand(time(NULL));
int dimension = atoi(argv[1]);
int** a = allocate_arr(dimension);
generateStandardMatrix(dimension, a);
printf("Array value : %d\n", a[0][0]);
int detVal = determinant(a, dimension);
printf("determinant value : %d\n", detVal);
// ... do more computations here, reusing `a` ...
deallocate_arr(dimension, a);
return 0;
}

Sorting Matrix with qsort function C++

Hello guys I need to know what should I pass to qsort function to make this work?
Everything else must stay as it is except arguments of qsort function.
#include <iostream>
#include <stdlib.h>
#include <math.h>
using namespace std;
void printMatrix(int **matrix, int n){
for(int i = 0; i<n; i++){
for(int j =0 ; j < n; j++)
cout<<matrix[i][j]<<" ";
cout<<endl;
}
}
void initMatrix(int **matrix, int n){
for(int i = 0; i<n; i++){
for(int j =0 ; j < n; j++){
matrix[i][j] = rand()%10;
}
}
}
int compar(const void *a, const void *b){
int ia = *((int*)a);
int ib = *((int*)b);
return ia-ib;
}
void deleteMatrix(int **matrix){
delete [] matrix;
}
int main()
{
cout<<"How many rows and cols?"<<endl;
int n;
cin>>n;
int **matrix;
matrix = new int* [n];
for(int j = 0; j < n; j++)
matrix[j] = new int[n];
initMatrix(matrix,n);
printMatrix(matrix,n);
cout<<"Sorted matrix:"<<endl;
qsort(matrix,n*n,sizeof(int),compar); //<-----------
printMatrix(matrix,n);
deleteMatrix(matrix);
return 0;
}
P.S
There must be ** pointer on matrix.
Thanks in advance!
You would probably be better off flattening the matrix to 1 dimension and using a step variable to determine where each row would start. Then sorting is easy.
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <math.h>
using namespace std;
void printMatrix(int *matrix, int matrixsize, int rowsize) {
for (int i = 0; i < matrixsize; i+= rowsize)
{
for (int j = 0; j < rowsize; j++)
{
cout << matrix[i + j] << " ";
}
cout << endl;
}
}
void initMatrix(int *matrix, int n)
{
for (int i = 0; i < n; i++)
{
matrix[i] = rand() % 10;
}
}
void deleteMatrix(int *matrix) {
delete[] matrix;
}
int main()
{
cout << "How many rows and cols?" << endl;
int row;
cin >> row;
int matrixSize = row*row;
int *matrix = new int[matrixSize];
initMatrix(matrix, matrixSize);
printMatrix(matrix, matrixSize, row);
cout << "Sorted matrix:" << endl;
sort(matrix,matrix + matrixSize); //<-----------
printMatrix(matrix, matrixSize, row);
deleteMatrix(matrix);
return 0;
}