#boost #stl #mpi #complex-numbers
#boost #stl #mpi #комплексные числа
Вопрос:
Похоже, что отправка сложных данных stl через механизм скелета / содержимого не работает.
Вот простой код, который показывает проблему:
#include <boost/mpi.hpp>
#include <boost/serialization/complex.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
namespace mpi = boost::mpi;
using namespace std;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
int NN=world.size();
int myid=world.rank();
if (myid == 0)
{
int N = 10;
vector <complex<double> > l(N);
for (int p=1; p!=NN; p )
{
int taskid=1;
world.send(p, 0, taskid);
world.send(p, 1, mpi::skeleton(l));
}
mpi::content c = mpi::get_content(l);
for (int n = 0; n!=l.size() ; n )
{
l[n]=complex<double>(1.0,1.0);
}
for (int p=1; p!=NN; p )
{
world.send(p, 1, c);
}
}
else if (myid == 2)
{
vector <complex<double> > l;
mpi::content c;
world.recv(0, 1, mpi::skeleton(l));
c = mpi::get_content(l);
world.recv(0, 1, c);
for (int n=0; n!=l.size(); n )
{
cout << l[n] << " ";
}
cout << endl;
}
}
Записи вектора l на выходе не являются (1.0, 1.0), но они кажутся
неинициализированный. Это происходит только в том случае, если используются сложные типы данных И
механизм скелета / содержимого.
Кто-нибудь знает, является ли это проблемой сборки, или я делаю что-то неправильно?
Ответ №1:
Недавно я столкнулся с аналогичной проблемой с одним из моих классов, и после некоторого пошагового выполнения процедуры сериализации в отладчике, я думаю, я понял, что происходит. Проблема заключается в использовании временных значений в операторах сериализации. В boost/serialization/complex.hpp функции сериализации выглядят следующим образом:
template<class Archive, class T>
inline void save(
Archive amp; ar,
std::complex< T > const amp; t,
const unsigned int /* file_version */
){
const T re = t.real();
const T im = t.imag();
ar << boost::serialization::make_nvp("real", re);
ar << boost::serialization::make_nvp("imag", im);
}
template<class Archive, class T>
inline void load(
Archive amp; ar,
std::complex< T >amp; t,
const unsigned int /* file_version */
){
T re;
T im;
ar >> boost::serialization::make_nvp("real", re);
ar >> boost::serialization::make_nvp("imag", im);
t = std::complex< T >(re,im);
}
Обратите внимание, что сериализация выполняется с помощью временных файлов. Функциональность get_content работает путем создания типа данных MPI, который на самом деле является картой расположения содержимого в памяти. При получении сообщения MPI копирует данные непосредственно в эти местоположения, без вызова каких-либо операторов сериализации. Проблема в том, что когда «save» использует временные данные, get_content() получит расположение не фактических данных, а временных, поэтому полученные данные помещаются не в нужное место.
У меня сложилось впечатление, что для работы функциональности скелета / содержимого функция сохранения (которая вызывает get_content()) должна напрямую и только сериализовать элементы данных объекта. В этом случае это невозможно, потому что у него нет доступа к внутреннему представлению complex . Я думаю, нужно было бы написать операторы сериализации как члены класса.
(Эти ограничения, похоже, вообще не упоминаются в документации Boost::MPI.)
Комментарии:
1. Обратите внимание, что это, похоже, влияет и на другие типы. Например, сериализация перечисления также использует временное значение, так что это также не работает со skeleta.
2. Спасибо за ответ. По крайней мере, теперь я знаю, что это невозможно сделать с помощью сборки в boost/ serialization/complex.hpp.
3. @tstollenw: (Очевидно, я не могу добавить комментарии к вашему ответу, поэтому вместо этого я комментирую здесь.) Я думаю, что ваш обходной путь не гарантированно сработает, потому что, по крайней мере, в некоторых спецификациях, похоже, говорится, что real() и imag() возвращают значение.
Ответ №2:
Вот возможное решение проблемы:
Я написал свою собственную сериализацию для сложных типов:
#include <boost/mpi.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
namespace mpi = boost::mpi;
using namespace std;
namespace boost
{
namespace serialization
{
template<class Archive>
void serialize(Archive amp; ar, complex<double> amp; g, const unsigned int version)
{
ar amp; g.real();
ar amp; g.imag();
}
}
}
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
int NN=world.size();
int myid=world.rank();
if (myid == 0)
{
int N = 10;
vector <complex<double> > l(N);
for (int p=1; p!=NN; p )
{
world.send(p, 1, mpi::skeleton(l));
}
mpi::content c = mpi::get_content(l);
for (int n = 0; n!=l.size() ; n )
{
l[n]=complex<double>(1.0,1.0);
}
for (int p=1; p!=NN; p )
{
world.send(p, 1, c);
}
}
else
{
vector <complex<double> > l;
mpi::content c;
world.recv(0, 1, mpi::skeleton(l));
c = mpi::get_content(l);
world.recv(0, 1, c);
for (int n=0; n!=l.size(); n )
{
cout << l[n] << " ";
}
cout << endl;
}
}
Ответ №3:
namespace boost {
namespace mpi {
template <>
struct is_mpi_datatype< complex<double> > : mpl::true_ { };
} }
использование этого может решить проблему. В оптимизации сериализации Boost