【问题标题】:How to serialize armadillo's vector如何序列化犰狳的向量
【发布时间】:2016-10-06 08:00:21
【问题描述】:

如何序列化arma::Col?下面是 MWE 和错误输出。

MWE:

#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <iostream>
#include "armadillo"

namespace mpi = boost::mpi;

struct S
{   
    int i;
    arma::Col<double>::fixed<3> cvector;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive& ar, const unsigned int version) 
    {
        ar& i;
        ar& cvector;
    }
};

int main()
{ 
    mpi::environment env;
    mpi::communicator world;

    S s;

    if (world.rank() == 0)
    {
        s.cvector[0] = 2;
        s.cvector[1] = 2;
        world.send(1, 0, s);
    }
    else
    {
        world.recv(0, 0, s);
        std::cout << s.cvector[0] << std::endl;
        std::cout << s.cvector[1] << std::endl;
    }

    return 0;
}

错误输出(跳过“需要”的东西):

error: ‘class arma::Col<double>::fixed<3ull>’ has no member named ‘serialize’; did you mean ‘set_size’? t.serialize(ar, file_version);

编辑: This 帖子似乎与我的问题有关,不幸的是它没有得到答复。

【问题讨论】:

    标签: c++ c++14 armadillo boost-serialization


    【解决方案1】:

    这里问题的真正症结在于您想向各种犰狳对象添加serialize() 成员函数,但这似乎是不可能的……除了巧妙地使用预处理器在犰狳中,它是!

    看看Mat_bones.hppCol_bones.hpp...你会在MatCol 的类定义中看到类似的内容:

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

    当我发现这个时,我很高兴,因为现在我可以做一些事情,比如定义一个名为 Mat_extra_bones.hpp 的文件:

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

    然后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);
    }
    

    那么,在你的程序中,你需要做的就是

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

    并且serialize() 函数将是Mat 类的成员。您可以轻松地将此解决方案应用于其他犰狳类型。

    事实上,这正是 mlpack 库 (http://www.mlpack.org/) 所做的,所以如果您有兴趣,可以仔细看看我在那里实现的确切解决方案:

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

    【讨论】:

    • 我应该补充一下,这是为Col 而不是Col::fixed 编写的,就像您正在使用的那样。所以可能需要进行一些小的修改。
    • 我知道这是一个很老的问题...我发现您的解决方案非常优雅,但是我在编译它时遇到了一些问题,特别是我收到错误“boost::serialization has not been声明“如果我按原样添加这些文件,而不是如果我在 Mat_extra_meat.hpp 中包含所有必要的头文件,我会收到错误 /usr/local/include/boost/type_traits/integral_constant.hpp:42:15: error: ' ::mpl_' 尚未使用 ::mpl_::bool_ 声明;您对如何编译和链接这些文件有任何提示吗?
    • 绝对不能在Mat_extra_meat.hpp 中包含标题,因为该文件中的任何内容都直接包含在 Mat 类中。所以,也许,在包含 &lt;armadillo&gt; 之前,您需要包含 &lt;boost/serialization.hpp&gt;
    【解决方案2】:

    由于 arm::Col::fixed 本身不支持序列化,您可以在 S 类中编写它,或者编写一个包装它并序列化它的类。我推荐第二个选项,因为它可以让你使用 arm::Col::fixed 任何你想要序列化而不重复的东西。

    【讨论】:

    • 谢谢,我在新答案中写下了您的建议。
    【解决方案3】:

    根据@UKMonkey 的回答,我写了一个工作示例。实际上对于这种情况,不需要将serialize 拆分为saveload

    #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;
    }
    

    【讨论】:

    • 您可能希望避免将任何内容放入 boost 命名空间中,除非您打算将其放入 boost... 这不太可能让您头疼,但它可以。加载到向量时,您可能希望考虑它可以处于任何状态......(可以是任何大小,可以有数据等)。除此之外 - 看起来它应该可以完成这项工作。
    • 但是saveload是在boost::serialization中定义的。
    • @Shibli :它们以使用 ADL 的方式调用,因此它们应该与它们正在影响的类型进入相同的命名空间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    相关资源
    最近更新 更多