2016-10-06 5 views
3

Как я могу сериализовать arma::Col? Ниже приведены MWE и выход ошибки.Как сериализовать вектор armadillo

MWE:

#include <boost/mpi/environment.hpp> 
#include <boost/mpi/communicator.hpp> 
#include <iostream> 
#include "armadillo" 

namespace mpi = boost::mpi; 

struct S 
{ 
    int i; 
    arma::Col<double>::fixed<3> cvector; 

    friend class boost::serialization::access; 

    template<class Archive> 
    void serialize(Archive& ar, const unsigned int version) 
    { 
     ar& i; 
     ar& cvector; 
    } 
}; 

int main() 
{ 
    mpi::environment env; 
    mpi::communicator world; 

    S s; 

    if (world.rank() == 0) 
    { 
     s.cvector[0] = 2; 
     s.cvector[1] = 2; 
     world.send(1, 0, s); 
    } 
    else 
    { 
     world.recv(0, 0, s); 
     std::cout << s.cvector[0] << std::endl; 
     std::cout << s.cvector[1] << std::endl; 
    } 

    return 0; 
} 

Выход ошибки (вприпрыжку "требуется от" материала):

error: ‘class arma::Col<double>::fixed<3ull>’ has no member named ‘serialize’; did you mean ‘set_size’? t.serialize(ar, file_version);

Edit:This пост, кажется, связано с моим вопросом и, к сожалению, он остается без ответа.

ответ

1

Поскольку arm :: Col :: fixed не поддерживает сериализацию, вы можете либо записать его в свой класс S, либо написать класс, который его обертывает и сериализует. Я бы рекомендовал второй вариант, так как он позволит вам использовать arm :: Col :: исправлено во всем, что вы хотите сериализовать, не повторяя.

+0

Спасибо, я написал то, что вы предложили в новом ответе. – Shibli

0

В соответствии с ответом @UKMonkey я написал рабочий пример. Фактически для этого случая нет необходимости разделять serialize на save и load.

#include <boost/mpi/environment.hpp> 
#include <boost/mpi/communicator.hpp> 
//#include <boost/serialization/split_free.hpp> 
#include <iostream> 
#include "armadillo" 

namespace mpi = boost::mpi; 

typedef arma::Col<double>::fixed<3> cvector; 

//BOOST_SERIALIZATION_SPLIT_FREE(cvector) 

namespace boost 
{ 
    namespace serialization 
    { 
     /*template<class Archive> 
     void save(Archive& ar, const cvector& cv, unsigned int) 
     { 
      std::cout << "saving" << std::endl; 
      ar& cv[0]; 
      ar& cv[1]; 
      ar& cv[2]; 
     } 
     template<class Archive> 
     void load(Archive& ar, cvector& cv, unsigned int) 
     { 
      std::cout << "loading" << std::endl; 
      ar& cv[0]; 
      ar& cv[1]; 
      ar& cv[2]; 
     }*/  
     template<class Archive> 
     inlide void serialize(Archive& ar, cvector& cv, unsigned int) 
     { 
      ar& cv[0]; 
      ar& cv[1]; 
      ar& cv[2]; 
     } 
    } 
} 

struct S 
{ 
    int i; 
    cvector c; 

    friend class boost::serialization::access; 

    template<class Archive> 
    void serialize(Archive& ar, const unsigned int) 
    { 
     ar& i; 
     ar& c; 
    } 
}; 

int main() 
{ 
    mpi::environment env; 
    mpi::communicator world; 

    S s; 

    if (world.rank() == 0) 
    { 
     s.i = 3; 
     s.c[0] = 2.; 
     s.c[1] = 4.; 
     world.send(1, 0, s); 
    } 
    else 
    { 
     world.recv(0, 0, s); 
     std::cout << s.i << std::endl; 
     std::cout << s.c[0] << std::endl; 
     std::cout << s.c[1] << std::endl; 
    } 

    return 0; 
} 
+1

Возможно, вы захотите избежать помещать что-либо в пространство имен boost, если только вы не планируете его поднять ... это вряд ли вызовет у вас головную боль, но это возможно. При загрузке в вектор вы можете подумать, что он может быть в любом состоянии ... (может быть любого размера, иметь данные и т. Д.). Кроме этого - похоже, что он должен выполнять эту работу. – UKMonkey

+0

Но 'save' и' load' определены в 'boost :: serialization'. – Shibli

+0

@Shibli: И они вызываются таким образом, чтобы использовать ADL, поэтому они должны находиться в том же пространстве имен, что и тип, который они производят. – ildjarn

2

Реальная суть вопроса здесь в том, что вы хотите добавить функцию в serialize() члены различных Armadillo объектов, но это не представляется возможным ... кроме того, что благодаря умному использованию препроцессор в Армадилло, это!

Взгляните на Mat_bones.hpp и Col_bones.hpp ... вы увидите что-то вроде этого, внутри определений классов из Mat и Col:

public: 

#ifdef ARMA_EXTRA_COL_PROTO 
    #include ARMA_INCFILE_WRAP(ARMA_EXTRA_COL_PROTO) 
#endif 

Это сделало меня очень счастлив, когда я нашел это, потому что Теперь я могу сделать что-то вроде определить файл с именем Mat_extra_bones.hpp:

//! Add a serialization operator. 
template<typename Archive> 
void serialize(Archive& ar, const unsigned int version); 

Mat_extra_meat.hpp, а затем:

// Add a serialization operator. 
template<typename eT> 
template<typename Archive> 
void Mat<eT>::serialize(Archive& ar, const unsigned int /* version */) 
{ 
    using boost::serialization::make_nvp; 
    using boost::serialization::make_array; 

    const uword old_n_elem = n_elem; 

    // This is accurate from Armadillo 3.6.0 onwards. 
    // We can't use BOOST_SERIALIZATION_NVP() because of the access::rw() call. 
    ar & make_nvp("n_rows", access::rw(n_rows)); 
    ar & make_nvp("n_cols", access::rw(n_cols)); 
    ar & make_nvp("n_elem", access::rw(n_elem)); 
    ar & make_nvp("vec_state", access::rw(vec_state)); 

    // mem_state will always be 0 on load, so we don't need to save it. 
    if (Archive::is_loading::value) 
    { 
    // Don't free if local memory is being used. 
    if (mem_state == 0 && mem != NULL && old_n_elem > arma_config::mat_prealloc) 
    { 
     memory::release(access::rw(mem)); 
    } 

    access::rw(mem_state) = 0; 

    // We also need to allocate the memory we're using. 
    init_cold(); 
    } 

    ar & make_array(access::rwp(mem), n_elem); 
} 

Тогда в вашей программе, все, что вам нужно сделать, это

#define ARMA_EXTRA_MAT_PROTO mat_extra_bones.hpp 
#define ARMA_EXTRA_MAT_MEAT mat_extra_meat.hpp 

и функция serialize() будет членом Mat класса. Вы можете легко адаптировать это решение для других типов Armadillo.

На самом деле это именно то, что mlpack библиотека (http://www.mlpack.org/) делает, так что если вы заинтересованы вы более внимательно посмотреть на точное решение, которое я реализованного может:

https://github.com/mlpack/mlpack/tree/master/src/mlpack/core/arma_extend

+0

Я должен добавить, это было написано для 'Col', а не' Col :: fixed', как вы используете. Поэтому могут потребоваться некоторые незначительные изменения. – ryan

Смежные вопросы