提升序列化犰狳矩阵

Boost serializing armadillo matrices

我试图确保序列化适用于矩阵,即犰狳,但我遇到了一些错误。

我制作了一个简单的随机矩阵示例,并尝试使用 boost 将内容保存在二进制文件中,然后使用 boost 加载它:

#include <iostream>
#include <fstream>
#include <boost/archive/tmpdir.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <armadillo>


int main() {

arma::mat A = arma::randu<arma::mat>(4,5);


std::ofstream outputStream;
outputStream.open("bin.dat");
std::ostringstream oss;
boost::archive::binary_oarchive oa(outputStream);
oa & A;
outputStream.close(); getting error

arma::mat B;
std::ifstream inputStream;
inputStream.open("bin.dat", std::ifstream::in);
boost::archive::binary_iarchive ia(inputStream);
ia & B;
return 0;


}

我收到以下错误(当 运行 命令时:g++ -std=c++11 arma_boost.cpp -larmadillo -lboost_serialization ):

In file included from /usr/include/boost/serialization/split_member.hpp:23:0,
                 from /usr/include/boost/serialization/nvp.hpp:33,
                 from /usr/include/boost/serialization/array.hpp:19,
                 from /usr/include/boost/archive/basic_binary_oprimitive.hpp:50,
                 from /usr/include/boost/archive/binary_oarchive_impl.hpp:22,
                 from /usr/include/boost/archive/binary_oarchive.hpp:21,
                 from arma_boost.cpp:4:
/usr/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = arma::Mat<double>]’:
/usr/include/boost/serialization/serialization.hpp:69:69:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = arma::Mat<double>]’
/usr/include/boost/serialization/serialization.hpp:128:27:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = arma::Mat<double>]’
/usr/include/boost/archive/detail/oserializer.hpp:152:5:   required from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::binary_oarchive; T = arma::Mat<double>]’
/usr/include/boost/archive/detail/oserializer.hpp:101:1:   required from ‘class boost::archive::detail::oserializer<boost::archive::binary_oarchive, arma::Mat<double> >’
/usr/include/boost/archive/detail/oserializer.hpp:253:13:   required from ‘static void boost::archive::detail::save_non_pointer_type<Archive>::save_standard::invoke(Archive&, const T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/detail/oserializer.hpp:308:28:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/common_oarchive.hpp:69:40:   required from ‘void boost::archive::detail::common_oarchive<Archive>::save_override(T&, int) [with T = const arma::Mat<double>; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/basic_binary_oarchive.hpp:75:7:   required from ‘void boost::archive::basic_binary_oarchive<Archive>::save_override(const T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/binary_oarchive_impl.hpp:51:9:   required from ‘void boost::archive::binary_oarchive_impl<Archive, Elem, Tr>::save_override(T&, int) [with T = const arma::Mat<double>; Archive = boost::archive::binary_oarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_oarchive.hpp:63:9:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = const arma::Mat<double>; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/detail/interface_oarchive.hpp:71:35:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator&(T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_oarchive]’
arma_boost.cpp:19:6:   required from here
/usr/include/boost/serialization/access.hpp:118:9: error: ‘class arma::Mat<double>’ has no member named ‘serialize’
         t.serialize(ar, file_version);
         ^
/usr/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = arma::Mat<double>]’:
/usr/include/boost/serialization/serialization.hpp:69:69:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = arma::Mat<double>]’
/usr/include/boost/serialization/serialization.hpp:128:27:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = arma::Mat<double>]’
/usr/include/boost/archive/detail/iserializer.hpp:192:5:   required from ‘void boost::archive::detail::iserializer<Archive, T>::load_object_data(boost::archive::detail::basic_iarchive&, void*, unsigned int) const [with Archive = boost::archive::binary_iarchive; T = arma::Mat<double>]’
/usr/include/boost/archive/detail/iserializer.hpp:120:1:   required from ‘class boost::archive::detail::iserializer<boost::archive::binary_iarchive, arma::Mat<double> >’
/usr/include/boost/archive/detail/iserializer.hpp:387:13:   required from ‘static void boost::archive::detail::load_non_pointer_type<Archive>::load_standard::invoke(Archive&, const T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/iserializer.hpp:439:28:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/common_iarchive.hpp:66:40:   required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:70:7:   required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/binary_iarchive_impl.hpp:50:9:   required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:60:9:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:67:32:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator&(T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
arma_boost.cpp:26:6:   required from here
/usr/include/boost/serialization/access.hpp:118:9: error: ‘class arma::Mat<double>’ has no member named ‘serialize’

编辑:

    #include <iostream>
    #include <fstream>
    #include <boost/archive/tmpdir.hpp>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/archive/binary_iarchive.hpp>
    #include <armadillo>

    namespace boost {
    namespace serialization {

    template<class Archive>
    void serialize(Archive & ar, arma::mat &m, const unsigned int version)
    {

        ar & m.n_cols;          
        ar & m.n_rows;          
        ar & m.n_elem;                      


    }

      }
      }


    int main() {


  arma::mat A = arma::randu<arma::mat>(4,5);

  std::ofstream outputStream;
  outputStream.open("bin.dat");
  std::ostringstream oss;
  boost::archive::binary_oarchive oa(outputStream);
  oa & A;
  outputStream.close();

  arma::mat b; //tried also arma::mat b(4,5);
  std::ifstream inputStream;
  inputStream.open("bin.dat", std::ifstream::in);
  boost::archive::binary_iarchive ia(inputStream);
  ia & b;


      return 0;
    }

这些是我收到的错误:

In file included from /usr/include/boost/archive/basic_text_oprimitive.hpp:34:0,
                 from /usr/include/boost/archive/text_oarchive.hpp:30,
                 from arma_boost.cpp:3:
/usr/include/boost/archive/detail/check.hpp: In instantiation of ‘void boost::archive::detail::check_const_loading() [with T = const unsigned int]’:
/usr/include/boost/archive/detail/iserializer.hpp:577:38:   required from ‘void boost::archive::load(Archive&, T&) [with Archive = boost::archive::binary_iarchive; T = const unsigned int]’
/usr/include/boost/archive/detail/common_iarchive.hpp:66:40:   required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&, int) [with T = const unsigned int; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:70:7:   required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&, int) [with T = const unsigned int; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/binary_iarchive_impl.hpp:50:9:   required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&, int) [with T = const unsigned int; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:60:9:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = const unsigned int; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:67:32:   [ skipping 8 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/common_iarchive.hpp:66:40:   required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:70:7:   required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/binary_iarchive_impl.hpp:50:9:   required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:60:9:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:67:32:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator&(T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
arma_boost.cpp:54:8:   required from here
/usr/include/boost/archive/detail/check.hpp:162:5: error: static assertion failed: typex::value
     BOOST_STATIC_ASSERT(typex::value);
     ^
In file included from /usr/include/boost/archive/binary_iarchive_impl.hpp:21:0,
                 from /usr/include/boost/archive/binary_iarchive.hpp:20,
                 from arma_boost.cpp:11:
/usr/include/boost/archive/basic_binary_iprimitive.hpp: In instantiation of ‘void boost::archive::basic_binary_iprimitive<Archive, Elem, Tr>::load(T&) [with T = const unsigned int; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’:
/usr/include/boost/archive/detail/iserializer.hpp:107:9:   required from ‘static void boost::archive::load_access::load_primitive(Archive&, T&) [with Archive = boost::archive::binary_iarchive; T = const unsigned int]’
/usr/include/boost/archive/detail/iserializer.hpp:362:46:   required from ‘static void boost::archive::detail::load_non_pointer_type<Archive>::load_primitive::invoke(Archive&, T&) [with T = const unsigned int; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/iserializer.hpp:439:28:   required from ‘static void boost::archive::detail::load_non_pointer_type<Archive>::invoke(Archive&, T&) [with T = const unsigned int; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/iserializer.hpp:592:24:   required from ‘void boost::archive::load(Archive&, T&) [with Archive = boost::archive::binary_iarchive; T = const unsigned int]’
/usr/include/boost/archive/detail/common_iarchive.hpp:66:40:   required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&, int) [with T = const unsigned int; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:70:7:   [ skipping 11 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/common_iarchive.hpp:66:40:   required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:70:7:   required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/binary_iarchive_impl.hpp:50:9:   required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&, int) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:60:9:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:67:32:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator&(T&) [with T = arma::Mat<double>; Archive = boost::archive::binary_iarchive]’
arma_boost.cpp:54:8:   required from here
/usr/include/boost/archive/basic_binary_iprimitive.hpp:88:35: error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
         load_binary(& t, sizeof(T));
                                   ^
/usr/include/boost/archive/basic_binary_iprimitive.hpp:149:1: note: initializing argument 1 of ‘void boost::archive::basic_binary_iprimitive<Archive, Elem, Tr>::load_binary(void*, std::size_t) [with Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>; std::size_t = long unsigned int]’
 basic_binary_iprimitive<Archive, Elem, Tr>::load_binary(
 ^

犰狳提供了一种将其类型保存到 HDF5 文件的方法,该方法运行良好并且可能对您来说已经足够了。

犰狳不支持提升序列化。从boost serialization tutorial我们可以看出,一个class必须有一个serialize方法才能用boost序列化。犰狳没有这样的方法,这就是你得到的错误。

或者,boost 还允许以非侵入方式使 class 使用它,这涉及实现 serialize 自由函数。由于您所需要的只是矩阵中的元素及其维度,因此在提升 serialization tutorial.

之后应该很容易实现

编辑完问题再编辑。

你得到的错误一开始确实很难查明原因,但如果你注释加载部分的行(return 之前的最后一行)你会发现它编译得很好。如果你 运行 可执行文件,二进制文件将被创建,因此序列化部分正在工作(但请记住你问题中的序列化函数尚未序列化元素)。

现在让我们回到错误

/usr/include/boost/archive/basic_binary_iprimitive.hpp:88:35: error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
         load_binary(& t, sizeof(T));

有一些 const 类型(被 boost 擦除,因此你得到 void *)不应该是 const。如果我们再看一下 serialize template 函数和教程,我们可以看到它同时用于序列化和加载,尽管在每种情况下 Archive 类型不同。这意味着在下面的代码中

ar & m.n_cols;          
ar & m.n_rows;          
ar & m.n_elem;  

在序列化过程中,值是从 m 中读取的(确定)。然而,在加载期间,值被写入 m,这是不正确的,因为这些是常量属性。那就是问题所在。为了解决这个问题,您需要将保存和加载拆分为单独的函数。然后,在 load 实现中,您可以使用其中一个犰狳构造函数从加载的数据创建一个新矩阵。最简单的方法是删除模板并为序列化函数创建两个重载

// This is the saving part
void serialize(boost::archive::binary_oarchive &ar, arma::mat &m,
               const unsigned int version) {

  ar &m.n_cols;
  ar &m.n_rows;
  ar &m.n_elem; // You don't really need this one

  // Note: You must also serialize the elements, which is currently missing
}

// This is the loading part
void serialize(boost::archive::binary_iarchive &ar, arma::mat &m,
               const unsigned int version) {

    // use one of the suitable constructors here
    m = arma::mat( ... )
}

两个序列化重载的可能完整实现如下所示(我通过打印 AB 矩阵测试了它们,它们是相同的)。最重要的是要记住,您必须按照保存值的相同顺序读取值。

void serialize(boost::archive::binary_oarchive &ar, arma::mat &m,
               const unsigned int version) {
  // Since this is used only for reading I prefer the "<<" symbol instead of
  // "&", but "&" would work just fine
  ar << m.n_cols;
  ar << m.n_rows;
  // Loop to save each element in order
  for (unsigned i = 0; i < m.n_elem; i++) {
    // memptr gives us a pointer to the raw memory used to store the elements
    ar << m.memptr()[i];
  }
}

void serialize(boost::archive::binary_iarchive &ar, arma::mat &m,
               const unsigned int version) {

  arma::uword n_cols;
  arma::uword n_rows;
  ar >> n_cols;
  ar >> n_rows;
  m = arma::mat(n_rows, n_cols);

  // Loop to read each element in order
  for (unsigned i = 0; i < m.n_elem; i++) {
    ar >> m.memptr()[i];
  }
}

免责声明:实际上我以前从未使用过 boost 序列化,因此可能有更好的方法来做到这一点。