2021-04-27

How to serialize sparse matrix in Armadillo and use with mpi implementation of boost?

I've been trying to serialize the sparse matrix from armadillo cpp library. I am doing some large-scale numerical computations, in which the data get stored in a sparse matrix, which I'd like to gather using mpi(Boost implementation) and sum over the matrices coming from different nodes. I'm stuck right now is how to send the sparse matrix from one node to other nodes. Boost suggests that to send user-defined objects (SpMat in this case) it needs to be serialized.

Boost's documentation gives a good tutorial on how to serialize a user-defined type and I can serialize some basic classes. Now, armadillo's SpMat class is very complicated for me to understand, and serialize.

I've come across few questions and their very elegant answers

  1. This answer by Ryan Curtin the co-author of Armadillo and author of mlpack has shown a very elegant way to serialize the Mat class.
  2. This answer by sehe shows a very simple way to serialize sparse matrix.

Using the first I can mpi::send a Mat class to another node in the communicator, but using the latter I couldn't do mpi::send.

This is adapted from the second linked answer

#include <iostream>
#include <boost/serialization/complex.hpp>
#include <boost/serialization/split_member.hpp>
#include <fstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <armadillo>
#include <boost/mpi.hpp>
namespace mpi = boost::mpi;
using namespace std;
using namespace arma;

namespace boost { 
    namespace serialization {

        template<class Archive>
            void save(Archive & ar, const arma::sp_mat &t, unsigned) {
                ar & t.n_rows;
                ar & t.n_cols;
                for (auto it = t.begin(); it != t.end(); ++it) {
                    ar & it.row() & it.col() & *it;
                }
            }

        template<class Archive>
            void load(Archive & ar, arma::sp_mat &t, unsigned) {
                uint64_t r, c;
                ar & r;
                ar & c;
                t.set_size(r, c);
                for (auto it = t.begin(); it != t.end(); ++it) {
                    double v;
                    ar & r & c & v;
                    t(r, c) = v;
                }
            }
    }}
BOOST_SERIALIZATION_SPLIT_FREE(arma::sp_mat)

int main(int argc, char *argv[])
{
    mpi::environment env(argc, argv);
    mpi::communicator world;
    arma::mat C(3,3, arma::fill::randu);
    C(1,1) = 0; //example so that a few of the components are u
    C(1,2) = 0;
    C(0,0) = 0;
    C(2,1) = 0;
    C(2,0) = 0;
    sp_mat A;
    if(world.rank() == 0) 
    {
        A = arma::sp_mat(C);
    }

    broadcast(world,A,0);

    if(world.rank() ==1 ) cout << A << endl;

    return 0;
}

I'm compiling like this

$ mpicxx -L ~/boost_1_73_0/stage/lib  -lboost_mpi -lboost_serialization -I ~/armadillo-9.900.1/include -DARMA_DONT_USE_WRAPPER -lblas -llapack serialize_arma_spmat.cpp -o serialize_arma_spmat

$ mpirun -np 2 serialize_arma_spmat
[matrix size: 3x3; n_nonzero: 0; density: 0%]

As process no. 2 didn't print the expected A matrix. So the broadcasting didn't work.

I couldn't try to build on Ryan's answer as I couldn't understand the sparse matrix implementation in "SpMat_Meat.hpp" in Armadillo which is very different from the Mat class.

How to serialize sparse matrix in boost so that it can be used in boost::mpi?



from Recent Questions - Stack Overflow https://ift.tt/3aZ066z
https://ift.tt/eA8V8J

No comments:

Post a Comment