How to serialize armadillo's vector

后端 未结 3 793
轻奢々
轻奢々 2020-12-20 01:27

How can I serialize arma::Col? Below are a MWE and the error output.

MWE:

#include 
#i         


        
相关标签:
3条回答
  • 2020-12-20 01:59

    Since arm::Col::fixed doesn't support serialisation itself, you can either write it in your S class, or write a class that wraps it and serialises it. I'd recommend the 2nd option since it will let you use arm::Col::fixed in anything that you want to serialise without repeating.

    0 讨论(0)
  • 2020-12-20 02:00

    According to @UKMonkey answer I wrote a working example. Actually for this case there is no need to split serialize tosave and load.

    #include <boost/mpi/environment.hpp>
    #include <boost/mpi/communicator.hpp>
    //#include <boost/serialization/split_free.hpp>
    #include <iostream>
    #include "armadillo"
    
    namespace mpi = boost::mpi;
    
    typedef arma::Col<double>::fixed<3> cvector;
    
    //BOOST_SERIALIZATION_SPLIT_FREE(cvector)
    
    namespace boost
    {   
        namespace serialization
        {
            /*template<class Archive>
            void save(Archive& ar, const cvector& cv, unsigned int)
            {
                std::cout << "saving" << std::endl;
                ar& cv[0];
                ar& cv[1];
                ar& cv[2];
            }
            template<class Archive>
            void load(Archive& ar, cvector& cv, unsigned int)
            {
                std::cout << "loading" << std::endl;
                ar& cv[0];
                ar& cv[1];
                ar& cv[2];
            }*/      
            template<class Archive>
            inlide void serialize(Archive& ar, cvector& cv, unsigned int)
            {
                ar& cv[0];
                ar& cv[1];
                ar& cv[2];
            }
        }
    } 
    
    struct S
    {
        int i;
        cvector c;
    
        friend class boost::serialization::access;
    
        template<class Archive>
        void serialize(Archive& ar, const unsigned int) 
        {
            ar& i;
            ar& c;
        }
    };
    
    int main()
    {
        mpi::environment env;
        mpi::communicator world;
    
        S s;
    
        if (world.rank() == 0)
        {
            s.i = 3;
            s.c[0] = 2.;
            s.c[1] = 4.;
            world.send(1, 0, s);
        }
        else
        {
            world.recv(0, 0, s);
            std::cout << s.i << std::endl;
            std::cout << s.c[0] << std::endl;
            std::cout << s.c[1] << std::endl;
        }
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-20 02:09

    The real crux of the issue here is that you want to add a serialize() member function to the various Armadillo objects, but that doesn't appear to be possible... except that thanks to a clever use of the preprocessor in Armadillo, it is!

    Take a look at Mat_bones.hpp and Col_bones.hpp... you'll see something like this, inside of the class definitions of Mat and Col:

    public:
    
    #ifdef ARMA_EXTRA_COL_PROTO
      #include ARMA_INCFILE_WRAP(ARMA_EXTRA_COL_PROTO)
    #endif
    

    It made me very happy when I found this, because now I can do something like define a file called Mat_extra_bones.hpp:

    //! Add a serialization operator.
    template<typename Archive>
    void serialize(Archive& ar, const unsigned int version);
    

    and then Mat_extra_meat.hpp:

    // Add a serialization operator.
    template<typename eT>
    template<typename Archive>
    void Mat<eT>::serialize(Archive& ar, const unsigned int /* version */)
    {
      using boost::serialization::make_nvp;
      using boost::serialization::make_array;
    
      const uword old_n_elem = n_elem;
    
      // This is accurate from Armadillo 3.6.0 onwards.
      // We can't use BOOST_SERIALIZATION_NVP() because of the access::rw() call.
      ar & make_nvp("n_rows", access::rw(n_rows));
      ar & make_nvp("n_cols", access::rw(n_cols));
      ar & make_nvp("n_elem", access::rw(n_elem));
      ar & make_nvp("vec_state", access::rw(vec_state));
    
      // mem_state will always be 0 on load, so we don't need to save it.
      if (Archive::is_loading::value)
      {
        // Don't free if local memory is being used.
        if (mem_state == 0 && mem != NULL && old_n_elem > arma_config::mat_prealloc)
        {
          memory::release(access::rw(mem));
        }
    
        access::rw(mem_state) = 0;
    
        // We also need to allocate the memory we're using.
        init_cold();
      }
    
      ar & make_array(access::rwp(mem), n_elem);
    }
    

    Then, in your program, all you need to do is

    #define ARMA_EXTRA_MAT_PROTO mat_extra_bones.hpp
    #define ARMA_EXTRA_MAT_MEAT mat_extra_meat.hpp
    

    and the serialize() function will be a member of the Mat class. You can easily adapt this solution for other Armadillo types.

    In fact this is exactly what the mlpack library (http://www.mlpack.org/) does, so if you are interested you can take a closer look at the exact solution I implemented there:

    https://github.com/mlpack/mlpack/tree/master/src/mlpack/core/arma_extend

    0 讨论(0)
提交回复
热议问题