Передайте матрицу Armadillo C++ через MPI

Мне нужно передать матрицу или сложный тип матрицы, определенный Matrix Library Armadillo C++, через MPI. Каков хороший способ сделать это? Я думал попробовать:

  1. Запишите матрицу в какой-нибудь массив, а затем отправьте
    строки/столбцы этого массива с помощью методов для удаления/восстановления массивов по обе стороны от MPI_send/recv

  2. Используя что-то вроде типа MPI_BYTE?

Спасибо

Обновлять

Поэтому я пытался реализовать другую схему, отправляя и получая, для простого примера, на одном узле.

перевести.cpp

    #include <mpi.h>
    #include <armadillo>
    #include <vector> 
    #include <cstdlib>

    using namespace std; 
    using namespace arma; 
    using std::vector; 

    class ArmadilloMPI
    {
        public:
            ArmadilloMPI(int nRows, int nCols)
            {
                this->nRows = nRows;
                this->nCols = nCols; 
                realArray = (double **)malloc(nCols * nRows * sizeof(double*));
                imArray = (double **)malloc(nCols * nRows * sizeof(double*));
            }

            ~ArmadilloMPI()
            {
                free(realArray[0]);
                free(realArray);
                free(imArray[0]);
                free(imArray);
            }

            double **realArray; 
            double **imArray; 
            int nCols; 
            int nRows; 

            cx_mat matConstructRecv(int src, int tag)
            {
                cx_mat A(nRows, nCols); 
                MPI_Recv(&(imArray[0][0]),  nRows * nCols, MPI_DOUBLE, src, tag, MPI_COMM_WORLD,0);
                MPI_Recv(&(realArray[0][0]),nRows * nCols, MPI_DOUBLE, src, tag, MPI_COMM_WORLD,0);

                for(int  i = 0; i < nRows; ++i )
                {
                    for(int j = 0; i < nCols; ++j)
                    {
                        real(A(i,j)) = *realArray[i * nRows + j]; 
                        imag(A(i,j)) = *imArray[i * nRows + j];
                    }
                }
                return A; 
            }

            void matDestroySend(cx_mat &A, int dest, int tag)
            {
                for(int  i = 0; i < nRows; ++i )
                {
                    for(int j = 0; i < nCols; ++j)
                    {
                        realArray[i * nRows + j]  = &real(A(i,j)); 
                        imArray[i * nRows + j] = &imag(A(i,j)); 
                    }
                }
                MPI_Send(&(realArray[0][0]), nRows * nCols, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD);
                MPI_Send(&(imArray[0][0]), nRows * nCols, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD);
            }
    };

    int main(int argc, char** argv)
    {
        MPI::Init(argc, argv);

        int size = MPI::COMM_WORLD.Get_size();
        int rank = MPI::COMM_WORLD.Get_rank();

        cout << "test"<<endl; 
        vector<cx_mat> world; 
        for(int i = 0; i < size; ++i )
        {
            world.push_back(randu<cx_mat>(4,4));
        }
        cx_mat A;
        A = randu<cx_mat>(4,4);

        ArmadilloMPI* armaMPI = new ArmadilloMPI(4,4); 

        if(rank==0)
        {

            for(int i = 1; i < size; i++)
            {   
                cout << "A is now " << A << endl; 
                A += armaMPI->matConstructRecv(i, 0);
            }
        }
        else
        {
            armaMPI->matDestroySend(world[rank], 1, 0);
        }

        cout << A << endl; 
        delete armaMPI;
        MPI::Finalize();
    }

Но у нас ошибка seg.

*** Process received signal *** 
Signal: Segmentation fault: 11 (11) 
Signal     code:     (0) 
Failing at address: 0x0 translate(1032,0x7fff747ad310) malloc: ***   error for object     0x41434d5f49504d4f: pointer being freed was not allocated

Мысли?


person user3819317    schedule 04.09.2014    source источник
comment
Я попробовал MPI_Bcast( &AAA(0,0), sizex*sizey*64, MPI_BYTE, 0, MPI_COMM_WORLD);, и он вызывает ошибку сегментации, как только AAA становится больше 16x16 или около того. Я бы выбрал первый вариант... Вас может заинтересовать ссылка MATMPIDENSE тип матрицы библиотеки PETSc. Здесь пример.   -  person francis    schedule 05.09.2014


Ответы (1)


Есть пара вопросов:

  • В c и c++ массив и вектор начинаются с 0, а не с 1. Таким образом, следующий код завершится ошибкой:

     vector<cx_mat> world; 
     world.resize(1);
     world[1] = randu<cx_mat>(4,4); //problem to come !
    

    Вы можете поменять на:

    vector<cx_mat> world;
    world.push_back(randu<cx_mat>(4,4));
    
  • Динамическое выделение 2D-массива с непрерывной памятью. Вам нужен один new для массива double, а другой new для массива указателей на double. Затем установите каждый указатель так, чтобы он указывал на первый элемент строки.

    double *data=new double[nCols * nRows ];
    realArray = new double*[( nRows )];
    for(int i=0;i<nRows;i++){
         realArray[i]=&data[i*nCols];
    }
    
  • Вы можете догадаться об этом... Почему компиляторы не предупреждают о подобных вещах? Потому что это могло иметь смысл, но не здесь.

    for(int j = 0; i < nCols; ++j)
    
  • Вы можете добавить разные теги к каждому сообщению, чтобы не переключать реальную часть и мнимую часть.

    MPI_Send(&(realArray[0][0]), nRows * nCols, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD);
    MPI_Send(&(imArray[0][0]), nRows * nCols, MPI_DOUBLE, dest, tag+1, MPI_COMM_WORLD);
    

Код становится:

#include <mpi.h>
#include <armadillo>
#include <vector>
#include <iostream>
#include <cstdlib>

using namespace std;
using namespace arma;
using std::vector;

class ArmadilloMPI
{
public:
    ArmadilloMPI(int nRows, int nCols)
    {
        this->nRows = nRows;
        this->nCols = nCols;
        double *data=new double[nCols * nRows ];
        realArray = new double*[( nRows )];
        for(int i=0;i<nRows;i++){
            realArray[i]=&data[i*nCols];
        }
        double *datai=new double[(nCols * nRows )];
        imArray =new double*[( nRows )];
        for(int i=0;i<nRows;i++){
            imArray[i]=&datai[i*nCols];
        }

    }

    ~ArmadilloMPI()
    {
        delete[] realArray[0];
        delete[] realArray;
        delete[] imArray[0];
        delete[] imArray;
    }

    double **realArray;
    double **imArray;
    int nCols;
    int nRows;

    cx_mat matConstructRecv(int tag, int src)
    {
        cx_mat A(nRows, nCols);
        MPI_Recv(&(imArray[0][0]),  nRows * nCols, MPI_DOUBLE, src, tag+1, MPI_COMM_WORLD,0);
        MPI_Recv(&(realArray[0][0]),nRows * nCols, MPI_DOUBLE, src, tag, MPI_COMM_WORLD,0);

        for(int  i = 0; i < nRows; ++i )
        {
            for(int j = 0; j < nCols; ++j)
            {
                real(A(i,j)) = realArray[i][j];
                imag(A(i,j)) = imArray[i][j];
            }
        }
        return A;
    }

    void matDestroySend(cx_mat &A, int dest, int tag)
    {
        for(int  i = 0; i < nRows; ++i )
        {
            for(int j = 0; j < nCols; ++j)
            {
                realArray[i][j] = real((A(i,j)));
                imArray[i][j] = imag((A(i,j)));
            }
        }
        MPI_Send(&(realArray[0][0]), nRows * nCols, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD);
        MPI_Send(&(imArray[0][0]), nRows * nCols, MPI_DOUBLE, dest, tag+1, MPI_COMM_WORLD);
    }
};

int main(int argc, char **argv)
{
    int rank;
    int size;
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    srand (time(NULL)+rank);

    vector<cx_mat> world;
    world.push_back(randu<cx_mat>(4,4));

    cx_mat A;
    ArmadilloMPI* armaMPI = new ArmadilloMPI(4,4);
    if(rank==0)
    {
        world[0].print("world[0] on 0:");

        armaMPI->matDestroySend(world[0], 1, 0);
    }
    if(rank==1){
        A = armaMPI->matConstructRecv(0, 0);
        A.print("A on 1:");
    }

    delete armaMPI;
    MPI_Finalize();
}

Скомпилировать :

 mpiCC -O2 -o main main.cpp -larmadillo -llapack -lblas -Wall

Бежать :

mpiexec -np 2 main
person francis    schedule 06.09.2014
comment
Большое спасибо. Да, это смешно, все вещи, которые вы не замечаете, пока это не будет опубликовано. - person user3819317; 07.09.2014