Skip to content

Instantly share code, notes, and snippets.

@ShigekiKarita
Last active November 12, 2021 12:44
Show Gist options
  • Save ShigekiKarita/4db2b0ffb207322c1324 to your computer and use it in GitHub Desktop.
Save ShigekiKarita/4db2b0ffb207322c1324 to your computer and use it in GitHub Desktop.
Eigen serialization
#ifndef matrix_utils_hpp
#define matrix_utils_hpp
#include <vector>
#include <array>
#include <type_traits>
#include <fstream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <msgpack.hpp>
namespace Matrix
{
namespace Util
{
extern void* enabler;
template <
class Matrix, class Value = typename Matrix::Scalar,
template < Value, class A = std::allocator<Value> >
class Container = std::vector,
typename std::enable_if_t<
Matrix::RowsAtCompileTime == -1 || Matrix::ColsAtCompileTime == -1
>*& = enabler
>
auto to_stl(const Matrix& matrix) -> decltype(auto)
{
return Container<Value>(matrix.data(), matrix.data() + matrix.size());
}
template <
class Matrix, class Value = typename Matrix::Scalar,
template < Value, std::size_t N >
class Container = std::array,
typename std::enable_if_t<
Matrix::RowsAtCompileTime != -1 && Matrix::ColsAtCompileTime != -1
>*& = enabler
>
auto to_stl(const Matrix& matrix) -> decltype(auto)
{
Container<Value, Matrix::RowsAtCompileTime * Matrix::ColsAtCompileTime > ret {};
for ( std::size_t i = 0; i < ret.size(); ++i )
{
ret[i] = *(matrix.data() + i);
}
return ret;
}
template < class Origin, class Value = typename Origin::Scalar >
struct Helper // for eigen
{
Helper() {}
Helper(const Origin& origin)
: _cols(origin.cols()), _data(to_stl(origin))
{}
template <class To = Origin >
To origin()
{
return To::Map(_data.data(), _data.size() / _cols, _cols);
}
const char* root() const
{
return _root_name.c_str();
}
MSGPACK_DEFINE(_cols, _data);
private:
std::size_t _cols;
std::vector<Value> _data;
std::string _root_name { "matrix" };
friend class boost::serialization::access;
template < class Archive >
void serialize(Archive& ar, unsigned int version)
{
static_cast< void >(version); // no use
ar & boost::serialization::make_nvp("cols", _cols);
ar & boost::serialization::make_nvp("data", _data);
}
};
template < class Origin >
void save(const Origin& origin, const std::string& save_path)
{
boost::filesystem::path path(save_path);
Helper<Origin> helper(origin);
if ( path.extension() == ".mpac" )
{
std::ofstream ofs(save_path, std::ios_base::binary);
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, helper);
ofs.write(sbuf.data(), sbuf.size());
}
else if ( path.extension() == ".bin" )
{
std::ofstream ofs(save_path, std::ios_base::binary);
boost::archive::binary_oarchive oar(ofs);
oar << helper;
}
else if ( path.extension() == ".xml" )
{
std::ofstream ofs(save_path);
boost::archive::xml_oarchive oar(ofs);
oar << boost::serialization::make_nvp(helper.root(), helper);
}
else // save as text
{
std::ofstream ofs(save_path);
boost::archive::text_oarchive oar(ofs);
oar << helper;
}
}
template < class Origin >
void load(Origin& origin, const std::string& load_path)
{
boost::filesystem::path path(load_path);
Helper<Origin> helper;
if ( path.extension() == ".mpac" )
{
std::ifstream ifs(load_path, std::ios_base::binary);
std::istreambuf_iterator<char> first(ifs);
std::istreambuf_iterator<char> last;
std::string data(first, last);
msgpack::unpacked msg;
msgpack::unpack(msg, data.data(), data.size());
msgpack::object obj = msg.get();
helper = obj.as<decltype(helper)>();
origin = std::move(helper.origin());
}
else if ( path.extension() == ".bin" )
{
std::ifstream ifs(load_path, std::ios_base::binary);
boost::archive::binary_iarchive iar(ifs);
iar >> helper;
origin = std::move(helper.origin());
}
else if ( path.extension() == ".xml" )
{
std::ifstream ifs(load_path);
boost::archive::xml_iarchive iar(ifs);
iar >> boost::serialization::make_nvp(helper.root(), helper);
origin = std::move(helper.origin());
}
else // load as text
{
std::ifstream ifs(load_path);
boost::archive::text_iarchive iar(ifs);
iar >> helper;
origin = std::move(helper.origin());
}
}
} // Util
} // Matrix
#endif // matrix_utils_hpp

For Eigen::MatrixXf::Random(4096, 4096)

  • boost/xml
    • serialization : 37.061291s
    • deserialization : 127.363071s
    • file size : 549MB
  • boost/bin
    • serialization : 0.115389s
    • deserialization : 0.127753s
    • file size : 66MB
  • msgpack
    • serialization : 0.338003s
    • deserialization : 1.666106s
    • file size : 81MB
#include "matrix_util.hpp"
#include <boost/test/minimal.hpp>
#include <Eigen/Core>
int test_main(int, char**)
{
std::string path = "./test.xml"; // *.txt/.bin/.mpac
// save
Eigen::MatrixXf A = Eigen::MatrixXf::Random(4, 3);
Matrix::Util::save(A, path);
// load
Eigen::MatrixXf B;
Matrix::Util::load(B, path);
// check
for ( std::size_t i = 0; i < A.rows(); ++i )
{
for ( std::size_t j = 0; j < A.cols(); ++j )
{
BOOST_CHECK(is_near(A(i, j), B(i, j)));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment