使用谷类库序列化Eigen :: Matrix [英] Serializing Eigen::Matrix using Cereal library

查看:303
本文介绍了使用谷类库序列化Eigen :: Matrix的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:在Google上搜索并阅读了代码中的doxygen注释后,我设法使其正常工作。问题是我在使用 resize()方法并且没有使用 std :: ios :: binary 之前错过了转换为溪流。如果您想做类似的事情,最好检查一下Azoth的答案。

UPDATED: I managed to get it to work after I googled around and read the doxygen comments in code. Problem was that I missed the cast before using resize() method and also not using std::ios::binary for the streams. If you want to do something similar, better check the answer by Azoth.

我正在尝试序列化 Eigen :: Matrix 使用谷类输入。这就是我所拥有的(松散地基于 https://gist.github.com/mtao/5798888以及谷物/类型)中的类型:

I am trying to serialize Eigen::Matrix type using Cereal. This is what I have (loosely based on https://gist.github.com/mtao/5798888 and the the types in cereal/types):

#include <cereal/cereal.hpp>
#include <cereal/archives/binary.hpp>
#include <Eigen/Dense>
#include <fstream>

namespace cereal
{
    template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
        typename std::enable_if<traits::is_output_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
        save(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> const & m)
    {
            int rows = m.rows();
            int cols = m.cols();
            ar(make_size_tag(static_cast<size_type>(rows * cols)));
            ar(rows);
            ar(cols);
            ar(binary_data(m.data(), rows * cols * sizeof(_Scalar)));
        }

    template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
        typename std::enable_if<traits::is_input_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
        load(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> const & m)
    {
            size_type size;
            ar(make_size_tag(size));

            int rows;
            int cols;
            ar(rows);
            ar(cols);

            const_cast<Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> &>(m).resize(rows, cols);

            ar(binary_data(const_cast<_Scalar *>(m.data()), static_cast<std::size_t>(size * sizeof(_Scalar))));
        }
}

int main() {
    Eigen::MatrixXd test = Eigen::MatrixXd::Random(10, 3);
    std::ofstream out = std::ofstream("eigen.cereal", std::ios::binary);
    cereal::BinaryOutputArchive archive_o(out);
    archive_o(test);

    std::cout << "test:" << std::endl << test << std::endl;

    out.close();

    Eigen::MatrixXd test_loaded;
    std::ifstream in = std::ifstream("eigen.cereal", std::ios::binary);
    cereal::BinaryInputArchive archive_i(in);
    archive_i(test_loaded);

    std::cout << "test loaded:" << std::endl << test_loaded << std::endl;
}


推荐答案

您的代码几乎正确,但有一些错误:

Your code is nearly correct but has a few mistakes:

您不需要进行 size_tag 的序列化,因为明确显示行和列。通常,谷物将 size_tag 用于可调整大小的容器,例如矢量或列表。即使矩阵可以调整大小,但仅对行和列进行显式序列化才有意义。

You don't need to be making the size_tag since you are serializing the number of rows and columns explicitly. Generally cereal uses size_tag for resizable containers like vectors or lists. Even though the matrix can resize, it makes more sense just to serialize the rows and columns explicitly.


  1. 您的加载函数应通过非const引用接受其参数

  2. 您不应使用使用 std :: ofstream 对象

  3. 更好的做法是让作用域和RAII处理<$的关闭/删除c $ c> std :: ofstream 以及谷物档案(二进制档案将立即清除其内容,但一般而言,谷物档案仅保证在销毁时清除其内容)

  1. Your load function should accept its parameter by non-const reference
  2. You shouldn't use operator= with the std::ofstream objects
  3. It's better practice to let scoping and RAII handle closing/tearing down of the std::ofstream as well as cereal archives (the binary archive will flush its contents immediately, but in general cereal archives are only guaranteed to flush their contents on destruction)

以下是在g ++和clang ++下编译并产生正确输出的版本:

Here's a version that compiles and produces correct output under g++ and clang++:

#include <cereal/cereal.hpp>
#include <cereal/archives/binary.hpp>
#include <Eigen/Dense>
#include <fstream>

namespace cereal
{
  template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
    typename std::enable_if<traits::is_output_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
    save(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> const & m)
    {
      int32_t rows = m.rows();
      int32_t cols = m.cols();
      ar(rows);
      ar(cols);
      ar(binary_data(m.data(), rows * cols * sizeof(_Scalar)));
    }

  template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
    typename std::enable_if<traits::is_input_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
    load(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> & m)
    {
      int32_t rows;
      int32_t cols;
      ar(rows);
      ar(cols);

      m.resize(rows, cols);

      ar(binary_data(m.data(), static_cast<std::size_t>(rows * cols * sizeof(_Scalar))));
    }
}

int main() {
  Eigen::MatrixXd test = Eigen::MatrixXd::Random(10, 3);

  {
    std::ofstream out("eigen.cereal", std::ios::binary);
    cereal::BinaryOutputArchive archive_o(out);
    archive_o(test);
  }

  std::cout << "test:" << std::endl << test << std::endl;

  Eigen::MatrixXd test_loaded;

  {
    std::ifstream in("eigen.cereal", std::ios::binary);
    cereal::BinaryInputArchive archive_i(in);
    archive_i(test_loaded);
  }

  std::cout << "test loaded:" << std::endl << test_loaded << std::endl;
}

这篇关于使用谷类库序列化Eigen :: Matrix的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆