0

Based on the excellent answers here, I tried to build a method to serialize Eigen tensors.

Based on the cereal package I tried the following:

namespace cereal
{
    template <class Archive, class Derived> inline
    typename std::enable_if<traits::is_output_serializable<BinaryData<typename Derived::Scalar>, Archive>::value, void>::type
    save(Archive & ar, Eigen::PlainObjectBase<Derived> const & m){
        const auto& d = m.dimensions();
        const int dims = d.size;
        for(int i=0;i<dims;i++)
        {
            ar(d[i]);
        }
        ar(binary_data(m.data(),m.size()*sizeof(typename Derived::Scalar)));
    }

    template <class Archive, class Derived> inline
    typename std::enable_if<traits::is_input_serializable<BinaryData<typename Derived::Scalar>, Archive>::value, void>::type
    load(Archive & ar, Eigen::PlainObjectBase<Derived> const & m){
        const auto& d = m.dimensions();
        const int dims = d.size;
        for(int i=0;i<dims;i++)
        {
            ar(d[i]);
        }
        ar(binary_data(m.data(),static_cast<std::size_t>(m.size()*sizeof(typename Derived::Scalar))));
    }
}

Together with the save/load pair:

Eigen::Tensor<double, 3> tensor3dmaus = {4, 3, 2};
tensor3dmaus.setValues( {{{1, 2}, {3, 4}, {5, 6}},
                     {{7, 8}, {9, 10}, {11, 12}},
                     {{13, 14}, {15, 16}, {17, 18}},
                     {{19, 20}, {21, 22}, {23, 24}}} );

{
    std::ofstream out("eigen.cereal", std::ios::binary);
    cereal::BinaryOutputArchive archive_o(out);
    archive_o(tensor3dmaus);
}

std::cout << "test:" << std::endl << tensor3dmaus << std::endl;

Tensor<double,3> 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;

However, when compiling, I obtain the following error message:

Types must either have a serialize function, load/save pair, or 

load_minimal/save_minimal pair (you may not mix these). 
 Serialize functions generally have the following signature: 

 template<class Archive> 
   void serialize(Archive & ar) 
   { 
     ar( member1, member2, member3 ); 
   } 

Can someone help me get this right? I tried to use Eigen's tensor base class instead of the PlainObject base with access level 3, which did not work unfortunately.

Any hints on how to adapt the code to function with tensors would be highly appreciated, thank you!

1 Answers1

0

I think your issue is that you have

load(Archive & ar, Eigen::PlainObjectBase<Derived> const & m){

instead of

load(Archive & ar, Eigen::PlainObjectBase<Derived> & m){

I had the following and it seemed to work fine:

namespace cereal
{

// binary serialization
template <class Archive, typename Scalar_, int NumIndices_, int Options_, typename IndexType_> inline
typename std::enable_if<cereal::traits::is_output_serializable<cereal::BinaryData<Scalar_>, Archive>::value, void>::type
save(Archive& ar, Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ > const & t)
{
  int numCells = 1;
  for (auto i = 0; i < NumIndices_; ++i)
  {
    int size = t.dimension(i);
    ar(size);
    numCells*=size;
  }
  ar(binary_data(t.data(), numCells * sizeof(Scalar_)));
}

template <class Archive, typename Scalar_, int NumIndices_, int Options_, typename IndexType_> inline
typename std::enable_if<cereal::traits::is_input_serializable<cereal::BinaryData<Scalar_>, Archive>::value, void>::type
load(Archive& ar, Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType_> & t)
{
  auto dims = t.dimensions();
  int numCells = 1;
  for (auto i = 0; i < NumIndices_; ++i)
  {
    int size;
    ar(size);
    dims[i] = size;
    numCells*=size;
  }
  t.resize(dims);
  ar(binary_data(t.data(), static_cast<std::size_t>(numCells * sizeof(Scalar_))));
}

}  // namespace cereal
ijnek
  • 1