Eigen和boost :: serialize

Gab*_*iel 8 c++ serialization templates boost eigen

我试着编写一个通用的序列化函数,它接受任何密集矩阵并将其序列化:其他一些有帮助但不是最终的问题 在这里: Question1 Question2

我尝试了以下哪些应该有效:

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
Run Code Online (Sandbox Code Playgroud)

当我尝试序列化时 Eigen::Matrix<double,4,4>

Eigen::Matrix<double,4,4> a; 
boost::serialize(ar, a);
Run Code Online (Sandbox Code Playgroud)

编译器可能以某种方式与上面的模板不匹配?并给出以下错误:

/usr/local/include/boost/serialization/access.hpp|118|error:'class Eigen :: Matrix'没有名为'serialize'的成员

Shm*_*ine 7

我已经测试了你的代码,当我尝试编译它时它也没有用.但是,基于Boost Serialize的文档,我的印象是它打算与流操作符<<一起使用.以下代码对我来说很好:

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;
}
Run Code Online (Sandbox Code Playgroud)

文件my_archive是在工作文件夹中创建的,具有非零值(只是内存中未初始化的垃圾,上面的过度简化代码).

编辑: 我尝试在我自己的应用程序中使用上面的确切代码,发现我收到了与您相同的错误.老实说,我现在不明白为什么会这样.我发现最简单的修复方法是替换Eigen::EigenBase<Derived>正在使用的实际Matrix类型.我正在使用的当前代码是:

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 ){ /* ... */ }
     }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码适用于任何标量类型(float,double,int)和动态/运行时大小的矩阵.对于静态大小,请相应地检入并更新模板参数.

编辑#2(2014年4月9日):

尽管上面的代码看起来很有效,但是当我尝试将它完全集成到我的代码中并使用适当的单元测试进行操作时,它就停止了工作.不幸的是,我给出的错误消息 - 无论是来自Visual Studio还是clang - 都是最无益的.幸运的是,gcc已经埋没在可怕的错误消息中,这是对CV-mismatch的引用,这似乎让我可以完全解决这个问题.

现在出现以下代码以便成功编译和运行.我试图使格式清晰易读(没有横向滚动) - 希望下面的代码是清楚的:

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
Run Code Online (Sandbox Code Playgroud)

以上代码的几个关键点:

  • 此代码现在具有所有Eigen的Matrix参数的模板化参数.这应该允许它适用于所有类型的矩阵和向量,无论是在编译时还是在运行时.这是对上述代码的重大改进

  • 必须将序列化代码拆分为单独的保存加载功能.否则,反序列化代码将不会调整矩阵的大小以保存原始数据.我相信Boost :: Serialize确实提供了一些额外的功能,可以重载以执行序列化或反序列化操作,但这种方法更容易实现.

  • 常量在预选赛save方法是必不可少的.在一个模糊的g ++错误引起我的注意之前,这就是我的麻烦的根源.

  • 我不能说我已经对这段代码进行了充分的压力测试.如果您(或其他任何人)发现任何问题,请告诉我,我会尝试跟进我发现的任何其他问题.

相信这会有所帮助.

什穆埃尔


iNF*_*TEi 6

我使用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_
Run Code Online (Sandbox Code Playgroud)

配置 Eigen 以使用此插件:(只需在包含任何 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_
Run Code Online (Sandbox Code Playgroud)

虽然我还没有真正彻底地测试过,但它运行良好,也可以处理 Array 或任何其他密集的特征对象。它也适用于像 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;
}
Run Code Online (Sandbox Code Playgroud)

还有一些测试代码:

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");
Run Code Online (Sandbox Code Playgroud)

更新:我做了一些小的修改,现在子矩阵的序列化也有效。


Jon*_*itt 6

这是一个更通用,更短的版本,具有以下功能:

  • 无论矩阵是行还是列主要,都能正常工作
  • 使用名称 - 值对,因此它适用于xml存档等
  • 不需要保存和加载版本之间的分割
  • 为Eigen :: Transform(Affine3d,Isometry3f等)添加一个包装函数
  • 对各种组合进行单元测试,例如,当您使用XML存档时保存列主要2x2 MatrixXd并将其作为行主要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
Run Code Online (Sandbox Code Playgroud)