如何序列化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帖子似乎与我的问题有关,遗憾的是它没有答案。
答案 0 :(得分:2)
这里问题的真正症结在于你想为各种犰狳物体添加一个serialize()
成员函数,但这看起来并不可能......除非是因为聪明在Armadillo中使用预处理器,它就是!
在Mat_bones.hpp
和Col_bones.hpp
的类定义中查看Mat
和Col
...您会看到类似的内容:< / p>
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
类的成员。您可以轻松地将此解决方案用于其他Armadillo类型。
实际上这正是mlpack库(http://www.mlpack.org/)所做的,所以如果你有兴趣,可以仔细看看我在那里实现的确切解决方案:
https://github.com/mlpack/mlpack/tree/master/src/mlpack/core/arma_extend
答案 1 :(得分:1)
由于arm :: Col :: fixed不支持序列化本身,你可以在S类中编写它,或者编写一个包装它并将其序列化的类。我建议使用第二个选项,因为它可以让你在任何想要序列化的东西中使用arm :: Col :: fixed而不重复。
答案 2 :(得分:0)
根据@UKMonkey的回答,我写了一个工作实例。实际上,对于这种情况,无需将serialize
拆分为save
和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;
}