Как правильно использовать встроенный `MPI_DOUBLE_COMPLEX` для` std :: complex & lt; double & gt; `с Boost.MPI?

Я хочу перевести большое количество std::complex<double> номера с использованием Boost.MPI. в Boost.MPI учебник объясняется, что

Для получения оптимальной производительности для небольших типов данных фиксированной длины не
содержащие любые указатели, очень важно пометить их, используя
черты типа Boost.MPI и Boost.Serialization.

Уже обсуждалось, что типы фиксированной длины, не содержащие
указатели можно использовать как is_mpi_datatypeНапример:

namespace boost { namespace mpi {   template <>   struct
is_mpi_datatype<gps_position> : mpl::true_ { }; } }

или эквивалентный макрос

BOOST_IS_MPI_DATATYPE(gps_position)

документация is_mpi_datatype приводит другой пример:

[…] Для этого сначала сделайте
тип данных Serializable (с использованием библиотеки Boost.Serialization);
затем специализировать is_mpi_datatype черта для point типа так
будет derive mpl::true_:

namespace boost { namespace mpi {
template<> struct is_mpi_datatype<point>
: public mpl::true_ { };
} }

Когда я пытаюсь сделать это точно для оптимизации производительности [Опции (A) или (B) в моей попытке ниже], я вижу, что Boost.MPI не использует встроенный тип данных MPI MPI_DOUBLE_COMPLEX и не отображается на MPI_SUM операция [утверждения (3) и (4) в моей попытке ниже]. Более того, включение одного из (A) или (B), а также отключение утверждений (3) и (4) приводит к ошибке сегментации во время выполнения.

В некоторый исходный файл Boost.MPI Я нашел недокументированный (?) Макрос с именем BOOST_MPI_DATATYPE который делает правильную вещь, но отмечен комментарием /// INTERNAL ONLY,

Перед тем, как приступить к реализации этого безобразного хака (?), Я хотел бы спросить: Какой способ сказать Boost.MPI использовать встроенный MPI_DOUBLE_COMPLEX тип данных для std::complex<double>?

#include <complex>
#include <functional>
#include <iostream>

#include <boost/mpi.hpp>
#include <boost/mpi/operations.hpp>
#include <boost/serialization/complex.hpp>

// tested with GCC 6.2.0, OpenMPI 2.0.1, boost 1.62.0
// mpic++ -lboost_mpi -lboost_serialization boost-mpi-complex.cpp

using dcomplex = std::complex<double>;
using dcplus = std::plus<dcomplex>;

////////////////////////////////////////////////////////////////////////////////
// How to pass assertions (1) to (5) below?
////////////////////////////////////////////////////////////////////////////////

// (A): documented, but fails assertions (2) and (3)
// if (2) and (3) are removed with this OPTION: segmentation fault at runtime
//BOOST_IS_MPI_DATATYPE(dcomplex)

// (B): documented, but same problems as (A)
namespace boost::mpi {
//template<> struct is_mpi_datatype<dcomplex> : boost::mpl::true_ {};
}

// (C): works, but not documented(?) and has `INTERNAL ONLY` comment in source
namespace boost::mpi {
//BOOST_MPI_DATATYPE(dcomplex, MPI_DOUBLE_COMPLEX, complex);
}

// (D): works, equivalent to (C)
// BUT if `is_mpi_complex_datatype` is specialized without `get_mpi_datatype`
// then compilation is fine with all assertions, but running yields segfault
namespace boost::mpi {
//template<> inline MPI_Datatype get_mpi_datatype<dcomplex>(const dcomplex&) {
//  return MPI_DOUBLE_COMPLEX;
//}
//template<> struct is_mpi_complex_datatype<dcomplex> : boost::mpl::true_ {};
}

// optional; works as expected for assertion (4)
namespace boost::mpi {
template<> struct is_commutative<dcplus, dcomplex> : mpl::true_ {};
}

// If these assertions are removed and none of (A) to (D) is activated then
// everything works as expected, but I would like to optimize serialization
static_assert(boost::mpi::is_mpi_datatype<dcomplex>{});                   // (1)
static_assert(boost::mpi::is_mpi_builtin_datatype<dcomplex>{});           // (2)

static_assert(boost::mpi::is_mpi_op<dcplus, dcomplex>{});                 // (3)
static_assert(boost::mpi::is_commutative<dcplus, dcomplex>{});            // (4)

static_assert(boost::serialization::is_bitwise_serializable<dcomplex>{}); // (5)

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

constexpr size_t N = 4;

dcomplex data[N]{};
if(0 == world.rank()) {
for(size_t i=0; i<N; ++i) data[i] = dcomplex{double(i), 0.0};
}
if(1 == world.rank()) {
for(size_t i=0; i<N; ++i) data[i] = dcomplex{0.0, double(N+i)};
}

all_reduce(world, boost::mpi::inplace(data), N, dcplus{});

if(0 == world.rank()) {
for(auto&& x : data) std::cout << x << std::endl;
}

return 0;
}

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …