Eigen and boost::serialize
Eigen and boost::serialize
我试图编写一个通用的序列化函数,它接受任何密集矩阵并对其进行序列化:以下是其他一些有帮助但并非最终的问题:问题1问题2
我尝试了以下应该有效的方法:
namespace boost {
namespace serialization {
template<class Archive, typename Derived> void serialize(Archive & ar, Eigen::EigenBase<Derived> & g, const unsigned int version)
{
ar & boost::serialization::make_array(g.derived().data(), g.size());
}
}; // namespace serialization
}; // namespace boost
当我尝试序列化Eigen::Matrix<double,4,4>
时
Eigen::Matrix<double,4,4> a;
boost::serialize(ar, a);
编译器会以某种方式与上面的模板不匹配吗?给出了以下错误:
/usr/local/include/boost/serialization/access.hpp|118|error:"class Eigen::Matrix"没有名为"serialize"的成员|
我已经测试了您的代码,当我试图编译它时它也不起作用。但是,根据boost serialize的文档,我认为它是用来与流运算符一起使用的<lt;。以下代码对我来说很好:
namespace boost {
namespace serialization {
template <class Archive, typename Derived>
void serialize( Archive & ar, Eigen::EigenBase<Derived> & g, const unsigned int version){
ar & boost::serialization::make_array(g.derived().data(), g.size());
}
}
}
int main (int argc, char* argv[]){
std::ofstream out("my_archive");
boost::archive::text_oarchive oa (out);
Eigen::Matrix <double, 4, 4> a;
out << a;
return 0;
}
文件my_archive是在具有非零值的工作文件夹中创建的(只是内存中未初始化的垃圾,上面的代码过于简化)。
编辑:我尝试在自己的应用程序中使用上面的代码,发现我收到了和您相同的错误。老实说,我现在不明白为什么。我发现的最简单的修复方法是用实际使用的矩阵类型替换Eigen::EigenBase<Derived>
。我目前使用的代码是:
namespace boost{
namespace serialization {
template <class Archive, typename Scalar>
void serialize ( Archive & ar, Eigen::Matrix<Scalar, -1, -1, 0, -1, -1> & g, const unsigned int version ){ /* ... */ }
}
}
上面的代码适用于任何标量类型(float、double、int)和动态/运行时大小的矩阵。对于静态大小,请检查并相应地更新模板参数。
第2版(2014年4月9日):
尽管上面的代码看起来可以工作,但当我试图将它完全集成到我的代码中,并通过适当的单元测试进行练习时,它停止了工作。不幸的是,我收到的错误消息——来自VisualStudio和clang——都是毫无帮助的。幸运的是,gcc已经隐藏在错误消息的可怕混乱中,这是对CV不匹配的引用,这似乎让我能够完全解决这个问题。
下面的代码现在显示为已成功编译并运行。我试着让格式清晰易读(没有侧滚动)——希望下面的代码是清晰的:
namespace boost{
namespace serialization{
template< class Archive,
class S,
int Rows_,
int Cols_,
int Ops_,
int MaxRows_,
int MaxCols_>
inline void save(
Archive & ar,
const Eigen::Matrix<S, Rows_, Cols_, Ops_, MaxRows_, MaxCols_> & g,
const unsigned int version)
{
int rows = g.rows();
int cols = g.cols();
ar & rows;
ar & cols;
ar & boost::serialization::make_array(g.data(), rows * cols);
}
template< class Archive,
class S,
int Rows_,
int Cols_,
int Ops_,
int MaxRows_,
int MaxCols_>
inline void load(
Archive & ar,
Eigen::Matrix<S, Rows_, Cols_, Ops_, MaxRows_, MaxCols_> & g,
const unsigned int version)
{
int rows, cols;
ar & rows;
ar & cols;
g.resize(rows, cols);
ar & boost::serialization::make_array(g.data(), rows * cols);
}
template< class Archive,
class S,
int Rows_,
int Cols_,
int Ops_,
int MaxRows_,
int MaxCols_>
inline void serialize(
Archive & ar,
Eigen::Matrix<S, Rows_, Cols_, Ops_, MaxRows_, MaxCols_> & g,
const unsigned int version)
{
split_free(ar, g, version);
}
} // namespace serialization
} // namespace boost
以上代码的几个关键点:
这个代码现在已经为所有的特征矩阵参数模板化了参数。这应该允许它处理所有类型的矩阵和向量,无论是在编译时还是在运行时调整大小。这是对上述代码的一个重大增强
序列化代码必须拆分为单独的save和load函数。否则,反序列化代码将不会调整矩阵的大小以容纳原始数据。我相信Boost::Serialize确实提供了一些额外的函数,这些函数可以重载以执行序列化或反序列化操作,但这种方法更容易实现。
save
方法上的const限定符是必不可少的。在一个不明显的g++错误让我陷入困境之前,这就是我麻烦的根源。我不能说我已经对这个代码进行了充分的压力测试。如果你(或其他任何人)发现它还有任何问题,请告诉我,我会尽力跟进我发现的其他问题。
相信这会有所帮助。
Shmuel
这里有一个更通用、更短的版本,具有以下功能:
- 无论矩阵是行还是列,都能正确工作
- 使用名称-值对,因此可以与xml档案等一起使用
- 不需要在保存和加载版本之间进行拆分
- 为Eigen::Transform(Affine3d、Isometry3f等)添加了一个包装函数
- 单元针对各种组合进行了测试,例如,当您保存列major 2x2 MatrixXd并在使用XML归档时将其加载为行major Eigen::Matrix时,它就可以工作了然而,这显然不适用于二进制或文本存档!在这些情况下,类型必须完全匹配
代码:
namespace boost { namespace serialization {
template< class Archive,
class S,
int Rows_,
int Cols_,
int Ops_,
int MaxRows_,
int MaxCols_>
inline void serialize(Archive & ar,
Eigen::Matrix<S, Rows_, Cols_, Ops_, MaxRows_, MaxCols_> & matrix,
const unsigned int version)
{
int rows = matrix.rows();
int cols = matrix.cols();
ar & make_nvp("rows", rows);
ar & make_nvp("cols", cols);
matrix.resize(rows, cols); // no-op if size does not change!
// always save/load row-major
for(int r = 0; r < rows; ++r)
for(int c = 0; c < cols; ++c)
ar & make_nvp("val", matrix(r,c));
}
template< class Archive,
class S,
int Dim_,
int Mode_,
int Options_>
inline void serialize(Archive & ar,
Eigen::Transform<S, Dim_, Mode_, Options_> & transform,
const unsigned int version)
{
serialize(ar, transform.matrix(), version);
}
}} // namespace boost::serialization
我使用了Eigen基于插件的扩展:
/**
* @file EigenDenseBaseAddons.h
*/
#ifndef EIGEN_DENSE_BASE_ADDONS_H_
#define EIGEN_DENSE_BASE_ADDONS_H_
friend class boost::serialization::access;
template<class Archive>
void save(Archive & ar, const unsigned int version) const {
derived().eval();
const Index rows = derived().rows(), cols = derived().cols();
ar & rows;
ar & cols;
for (Index j = 0; j < cols; ++j )
for (Index i = 0; i < rows; ++i )
ar & derived().coeff(i, j);
}
template<class Archive>
void load(Archive & ar, const unsigned int version) {
Index rows, cols;
ar & rows;
ar & cols;
if (rows != derived().rows() || cols != derived().cols() )
derived().resize(rows, cols);
ar & boost::serialization::make_array(derived().data(), derived().size());
}
template<class Archive>
void serialize(Archive & ar, const unsigned int file_version) {
boost::serialization::split_member(ar, *this, file_version);
}
#endif // EIGEN_DENSE_BASE_ADDONS_H_
配置Eigen以使用此pulgin:(只需在包含任何Eigen标头之前定义宏)
#ifndef EIGEN_CONFIG_H_
#define EIGEN_CONFIG_H_
#include <boost/serialization/array.hpp>
#define EIGEN_DENSEBASE_PLUGIN "EigenDenseBaseAddons.h"
#include <Eigen/Core>
#endif // EIGEN_CONFIG_H_
虽然我还没有真正测试过,但它工作得很好,也可以处理Array或任何其他密集的Eigen对象。它也适用于vec.tail<4> (),但对于mat.topRows<2> ()或块操作。(参见更新:现在也适用于子矩阵)
与目前的其他答案相比,这适用于更多的表达式集,并且可能避免一些临时的。通过将PlainObjectBase<Derived>
对象传递给序列化函数,也可能实现非侵入性版本。。
/// Boost Serialization Helper
template <typename T>
bool serialize(const T& data, const std::string& filename) {
std::ofstream ofs(filename.c_str(), std::ios::out);
if (!ofs.is_open())
return false;
{
boost::archive::binary_oarchive oa(ofs);
oa << data;
}
ofs.close();
return true;
}
template <typename T>
bool deSerialize(T& data, const std::string& filename) {
std::ifstream ifs(filename.c_str(), std::ios::in);
if (!ifs.is_open())
return false;
{
boost::archive::binary_iarchive ia(ifs);
ia >> data;
}
ifs.close();
return true;
}
还有一些测试代码:
VectorXf vec(100);
vec.setRandom();
serializeText(vec.tail<5>(), "vec.txt");
MatrixXf vec_in;
deSerialize(vec_in, "vec.bin");
assert(vec_in.isApprox(vec.tail<5>()));
serialize(Vector2f(0.5f,0.5f), "a.bin");
Vector2f a2f;
deSerializeBinary(a2f, "a.bin");
assert(a2f.isApprox(Vector2f(0.5f,0.5f)));
VectorXf axf;
deSerialize(axf, "a.bin");
assert(aXf.isApprox(Vector2f(0.5f,0.5f)));
boost::shared_ptr<Vector4f> b = boost::make_shared<Vector4f>(Vector4f::Random());
serialize(b, "b.tmp");
boost::shared_ptr<Vector4f> b_in;
deSerialize(b_in, "b.tmp");
BOOST_CHECK_EQUAL(*b, *b_in);
Matrix4f m(Matrix4f::Random());
serialize(m.topRows<2>(), "m.bin");
deSerialize(m_in, "m.bin");
更新:我做了一些小的修改,现在子矩阵的序列化也可以了。
- 理解boost::asio-async_read在无需读取内容时的行为
- boost::进程间消息队列引发错误
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- cmake如何在fedora工作站中找到boost静态库包
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- Boost Graph Library,修复节点大小
- 什么是"#include <boost/functional/hash.hpp> "?
- 基于boost的程序的静态链接——zlib问题
- C++:如何在CLion IDE中安装Boost
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何在boost beast http请求中设置http头
- Boost Spirit,获取迭代器内部语义动作
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- 使用 boost::serialize (使用 SSCCE) 反序列化多个值
- Eigen and boost::serialize
- 使用Boost:serialize反序列化指向派生类的指针时出现问题
- 如何重写boost::serialize获得指向对象的指针时发生的情况
- boost::Serialize VS std::fstream
- 为什么 boost::serialize 不起作用,尽管一切看起来都正确?( "unregistered class" )
- 将 boost::serialization::serialize'ble 结构作为二进制文件存储到硬盘上