c++ - Serializing Eigen::Matrix using Cereal library -
updated: managed work after googled around , read doxygen comments in code. problem missed cast before using resize()
method , not using std::ios::binary
streams. if want similar, better check answer azoth.
i trying serialize eigen::matrix
type using cereal. have (loosely based on https://gist.github.com/mtao/5798888 , 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 correct has few mistakes:
you don't need making size_tag
since serializing number of rows , columns explicitly. cereal uses size_tag
resizable containers vectors or lists. though matrix can resize, makes more sense serialize rows , columns explicitly.
- your load function should accept parameter non-const reference
- you shouldn't use operator=
std::ofstream
objects - it's better practice let scoping , raii handle closing/tearing down of
std::ofstream
cereal archives (the binary archive flush contents immediately, in general cereal archives guaranteed flush contents on destruction)
here's version compiles , produces correct output under 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; }
Comments
Post a Comment