Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
373 views
in Technique[技术] by (71.8m points)

c++ - Eigen and boost::serialize

I tried to write a generic serialize function which takes any dense matrix and serializes it: Some other questions which help but not to the end are here: Question1 Question2

I tried the following which should work:

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

When I try to serialize an Eigen::Matrix<double,4,4>

Eigen::Matrix<double,4,4> a; 
boost::serialize(ar, a);

The compiler can somehow not match the template above? And the following errors are given :

/usr/local/include/boost/serialization/access.hpp|118|error: 'class Eigen::Matrix' has no member named 'serialize'|

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I've tested out your code and it also did not work when I tried to compile it. However, based on the documentation for Boost Serialize, I am under the impression that it is intended to be used with the stream operator <<. The following code works fine for me:

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;
}

The file my_archive is created in the working folder with non-zero values (just the uninitialized garbage in memory, with the above over-simplified code).

EDIT: I tried using the exact code above in my own application and found that I received the same error as you did. I honestly do not understand why that it, right now. The simplest fix that I found was to replace Eigen::EigenBase<Derived> with the actual Matrix type being used. The current code that I am using is:

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 ){ /* ... */ }
     }
}

The above code works for any scalar type (float, double, int) and for dynamic/runtime sized matrixes. For static sized, check into and update the template parameters accordingly.

EDIT #2 (April 09, 2014):

Despite the appearance of the above code working, when I tried to integrate it fully into my code and exercise it with appropriate unit testing, it stopped working. Unfortunately, the error messages that I was being given -- both from Visual Studio and clang -- were most unhelpful. Fortunately, gcc had buried within the horrible mess of error messages, a reference to CV-mismatch, which seems to have allowed me to fully address this.

The following code now appears to compile and run successfully. I've tried to make the formatting legible (without side-scrolling) -- hopefully the code below is clear:

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

A few critical points on the above code:

  • This code now has templated parameters for all of Eigen's Matrix parameters. This should allow it to work with all types of matrices and vectors, whether sized at compile-time or run-time. This is a major enhancement over the above code

  • It is essential that the serialization code be split into separate save and load functions. Otherwise, the deserialization code will not resize the matrix to hold the original data. I believe that Boost::Serialize does provide some additional functions that can be overloaded to perform operations on serialization or deserialization, but this approach was easier to implement.

  • The const qualifier on the save method is essential. This was the source of my troubles before an obscure g++ error keyed me in on this.

  • I cannot say that I have fully stress-tested this code yet. If you (or anyone else) finds any more problems with it, please do let me know and I'll try and follow up with anything else that I find.

Trust that that helps.

Shmuel


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...