序列化特征::使用谷物库的矩阵
Serializing Eigen::Matrix using Cereal library
>UPDATE:在我用谷歌搜索并阅读代码中的doxygen注释后,我设法让它工作。问题是我在使用resize()
方法之前错过了演员表,也没有对流使用std::ios::binary
。如果你想做类似的事情,最好看看Azoth的答案。
我正在尝试使用 Cereal 序列化Eigen::Matrix
类型。这就是我所拥有的(松散地基于 https://gist.github.com/mtao/5798888 和 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;
}
你的代码几乎是正确的,但有一些错误:
您无需进行size_tag
,因为您要显式序列化行数和列数。 通常,谷物将size_tag
用于可调整大小的容器,如矢量或列表。 即使矩阵可以调整大小,仅显式序列化行和列更有意义。
- 加载函数应通过非常量引用接受其参数
- 不应将 operator= 与
std::ofstream
对象一起使用 - 更好的做法是让范围界定和 RAII 处理
std::ofstream
和谷物档案的关闭/拆除(二进制档案将立即刷新其内容,但一般来说,谷物档案只能保证在销毁时刷新其内容)
这是一个在 g++ 和 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;
}
基于@Azoth答案(无论如何,我想给他全部功劳),我将模板改进了一点
- 也为
Eigen::Array
工作(而不仅仅是Eigen::Matrix
); - 不序列化编译时维度(例如,这会产生相当大的存储差异
Eigen::Vector3f
)。
结果如下:
namespace cereal
{
template <class Archive, class Derived> inline
typename std::enable_if<traits::is_output_serializable<BinaryData<typename Derived::Scalar>, Archive>::value, void>::type
save(Archive & ar, Eigen::PlainObjectBase<Derived> const & m){
typedef Eigen::PlainObjectBase<Derived> ArrT;
if(ArrT::RowsAtCompileTime==Eigen::Dynamic) ar(m.rows());
if(ArrT::ColsAtCompileTime==Eigen::Dynamic) ar(m.cols());
ar(binary_data(m.data(),m.size()*sizeof(typename Derived::Scalar)));
}
template <class Archive, class Derived> inline
typename std::enable_if<traits::is_input_serializable<BinaryData<typename Derived::Scalar>, Archive>::value, void>::type
load(Archive & ar, Eigen::PlainObjectBase<Derived> & m){
typedef Eigen::PlainObjectBase<Derived> ArrT;
Eigen::Index rows=ArrT::RowsAtCompileTime, cols=ArrT::ColsAtCompileTime;
if(rows==Eigen::Dynamic) ar(rows);
if(cols==Eigen::Dynamic) ar(cols);
m.resize(rows,cols);
ar(binary_data(m.data(),static_cast<std::size_t>(rows*cols*sizeof(typename Derived::Scalar))));
}
}
相关文章:
- 如何在C++中序列化结构数据
- 序列化,没有库的整数,得到奇怪的结果
- 如何知道QDataStream不能反序列化某些内容
- 如何使用Python从C++中读取谷物序列化数据
- 如何使用boost::具有嵌套结构和最小代码更改的序列化
- 带有Protobuf序列化的C++Hazelcast:字符串不是UTF-8格式的
- 自定义对象的dlib序列化在gcc中失败
- C++boost序列化多态性问题
- 增强基于 XML class_id的反序列化
- 提升反序列化对象具有 nan 或 -nan 值
- 在 cpp 中的平面缓冲区中序列化对象
- 每次进行继承时都需要提升::序列化::base_object吗?
- 如何在 c++ 非托管代码中反序列化 byte[] 的 json 字符串?
- 特征模板化函数和维度
- 提升序列化 1:73 的向后兼容性问题
- 将 boost 序列化对象的 asio::streambuf 表示转换为 Beast 的 DynamicBody req.body()
- 特征矩阵+Boost::序列化/C++17
- 从特征(SparseLU对象)序列化分解矩阵
- boost序列化特征矩阵为XML
- 序列化特征::使用谷物库的矩阵