19#ifndef TIMPI_PARALLEL_IMPLEMENTATION_H
20#define TIMPI_PARALLEL_IMPLEMENTATION_H
48#ifdef TIMPI_DEFAULT_QUADRUPLE_PRECISION
49# include <boost/multiprecision/float128.hpp>
54#define TIMPI_LOG_SCOPE(f,c)
104template <
typename T,
typename A1,
typename A2>
105inline void pack_vector_bool(
const std::vector<bool,A1> & vec_in,
106 std::vector<T,A2> & vec_out)
108 unsigned int data_bits = 8*
sizeof(T);
109 std::size_t in_size = vec_in.size();
110 std::size_t out_size = in_size/data_bits + ((in_size%data_bits)?1:0);
112 vec_out.resize(out_size);
113 for (std::size_t i=0; i != in_size; ++i)
115 std::size_t index = i/data_bits;
116 std::size_t offset = i%data_bits;
117 vec_out[index] += (vec_in[i]?1u:0u) << offset;
124template <
typename T,
typename A1,
typename A2>
125inline void unpack_vector_bool(
const std::vector<T,A1> & vec_in,
126 std::vector<bool,A2> & vec_out)
128 unsigned int data_bits = 8*
sizeof(T);
130 std::size_t out_size = vec_out.size();
131 timpi_assert_equal_to
132 (out_size/data_bits + (out_size%data_bits?1:0), vec_in.size());
134 for (std::size_t i=0; i != out_size; ++i)
136 std::size_t index = i/data_bits;
137 std::size_t offset = i%data_bits;
138 vec_out[i] = (vec_in[index] >> offset) & 1;
146template <
typename T1,
typename T2,
typename A1,
typename A2,
typename A3,
typename A4>
147inline void send_receive_vec_of_vec(
const unsigned int dest_processor_id,
148 const std::vector<std::vector<T1,A1>,A2> & send_data,
149 const unsigned int source_processor_id,
150 std::vector<std::vector<T2,A3>,A4> & recv_data,
155 TIMPI_LOG_SCOPE(
"send_receive()",
"Parallel");
157 if (dest_processor_id == comm.
rank() &&
158 source_processor_id == comm.
rank())
160 recv_data = send_data;
165 comm.
send (dest_processor_id, send_data, req, send_tag);
166 comm.
receive (source_processor_id, recv_data, recv_tag);
200std::pair<data_type, std::unique_ptr<StandardType<std::pair<T,int>>>>
203 std::pair<data_type, std::unique_ptr<StandardType<std::pair<T,int>>>>
return_val;
217# define TIMPI_COUNT_TYPE MPI_COUNT
218# define TIMPI_PACK_SIZE MPI_Pack_size_c
219# define TIMPI_SEND MPI_Send_c
220# define TIMPI_SSEND MPI_Ssend_c
221# define TIMPI_ALLREDUCE MPI_Allreduce_c
222# define TIMPI_IALLREDUCE MPI_Iallreduce_c
223# define TIMPI_ISEND MPI_Isend_c
224# define TIMPI_ISSEND MPI_Issend_c
225# define TIMPI_PACK MPI_Pack_c
226# define TIMPI_UNPACK MPI_Unpack_c
227# define TIMPI_RECV MPI_Recv_c
228# define TIMPI_IRECV MPI_Irecv_c
229# define TIMPI_SENDRECV MPI_Sendrecv_c
230# define TIMPI_ALLGATHERV MPI_Allgatherv_c
231# define TIMPI_ALLGATHER MPI_Allgather_c
232# define TIMPI_BCAST MPI_Bcast_c
233# define TIMPI_GATHER MPI_Gather_c
234# define TIMPI_GATHERV MPI_Gatherv_c
235# define TIMPI_SCATTER MPI_Scatter_c
236# define TIMPI_SCATTERV MPI_Scatterv_c
237# define TIMPI_ALLTOALL MPI_Alltoall_c
240# define TIMPI_COUNT_TYPE MPI_INT
241# define TIMPI_PACK_SIZE MPI_Pack_size
242# define TIMPI_SEND MPI_Send
243# define TIMPI_SSEND MPI_Ssend
244# define TIMPI_ALLREDUCE MPI_Allreduce
245# define TIMPI_IALLREDUCE MPI_Iallreduce
246# define TIMPI_ISEND MPI_Isend
247# define TIMPI_ISSEND MPI_Issend
248# define TIMPI_PACK MPI_Pack
249# define TIMPI_UNPACK MPI_Unpack
250# define TIMPI_RECV MPI_Recv
251# define TIMPI_IRECV MPI_Irecv
252# define TIMPI_SENDRECV MPI_Sendrecv
253# define TIMPI_ALLGATHERV MPI_Allgatherv
254# define TIMPI_ALLGATHER MPI_Allgather
255# define TIMPI_BCAST MPI_Bcast
256# define TIMPI_GATHER MPI_Gather
257# define TIMPI_GATHERV MPI_Gatherv
258# define TIMPI_SCATTER MPI_Scatter
259# define TIMPI_SCATTERV MPI_Scatterv
260# define TIMPI_ALLTOALL MPI_Alltoall
265template <
typename T,
typename A1,
typename A2>
281 for (std::size_t
i = 0;
i !=
n_vecs; ++
i)
292 type, this->
get(), &packedsize));
304 const std::basic_string<T> &
buf,
325 const std::basic_string<T> &
buf,
343 req.add_post_wait_work
388 req.add_post_wait_work
394template <
typename T,
typename C,
typename A>
396 const std::set<T,C,A> &
buf,
399 this->
send(dest_processor_id,
buf,
405template <
typename T,
typename C,
typename A>
407 const std::set<T,C,A> &
buf,
409 const MessageTag & tag)
const
411 this->
send(dest_processor_id,
buf,
417template <
typename T,
typename C,
typename A>
419 const std::set<T,C,A> &
buf,
420 const DataType & type,
421 const MessageTag & tag)
const
426 this->
send(dest_processor_id,
vecbuf, type, tag);
431template <
typename T,
typename C,
typename A>
433 const std::set<T,C,A> &
buf,
434 const DataType & type,
436 const MessageTag & tag)
const
443 new std::vector<T,A>(
buf.begin(),
buf.end());
446 req.add_post_wait_work
447 (
new PostWaitDeleteBuffer<std::vector<T,A>>(
vecbuf));
454template <
typename T,
typename A>
456 const std::vector<T,A> &
buf,
457 const MessageTag & tag)
const
459 this->
send(dest_processor_id,
buf,
465template <
typename T,
typename A,
466 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
468 const std::vector<T,A> &
buf,
470 const MessageTag & tag)
const
472 this->
send(dest_processor_id,
buf,
476template <
typename T,
typename A,
477 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
479 const std::vector<T,A> &
buf,
481 const MessageTag & tag)
const
492template <
typename T,
typename A>
494 const std::vector<T,A> &
buf,
495 const DataType & type,
496 const MessageTag & tag)
const
510template <
typename T,
typename A,
typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
512 const std::vector<T,A> &
buf,
513 const DataType & type,
515 const MessageTag & tag)
const
529 req.add_post_wait_work
530 (
new PostWaitDereferenceTag(tag));
533template <
typename T,
typename A,
typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
535 const std::vector<T,A> &
buf,
536 const NotADataType &,
538 const MessageTag & tag)
const
554template <
typename T,
typename A1,
typename A2>
556 const std::vector<std::vector<T,A1>,
A2> &
buf,
557 const MessageTag & tag)
const
559 this->
send(dest_processor_id,
buf,
566template <
typename T,
typename A1,
typename A2>
568 const std::vector<std::vector<T,A1>,
A2> &
buf,
570 const MessageTag & tag)
const
572 this->
send(dest_processor_id,
buf,
579template <
typename T,
typename A1,
typename A2>
581 const std::vector<std::vector<T,A1>,
A2> &
buf,
582 const DataType & type,
583 const MessageTag & tag)
const
588 this->
send(dest_processor_id,
buf, type,
req, tag);
594template <
typename T,
typename A1,
typename A2>
596 const std::vector<std::vector<T,A1>,
A2> &
send_vecs,
597 const DataType & type,
599 const MessageTag & tag)
const
620 for (std::size_t
i = 0;
i !=
n_vecs; ++
i)
640 req.add_post_wait_work
641 (
new PostWaitDeleteBuffer<std::vector<char>> (
sendbuf));
647template <
typename Context,
typename Iter>
657 typedef typename std::iterator_traits<Iter>::value_type T;
672 std::vector<typename Packing<T>::buffer_type>
buffer;
695template <
typename Context,
typename Iter>
706 typedef typename std::iterator_traits<Iter>::value_type T;
736 std::vector<buffer_t> *
buffer =
new std::vector<buffer_t>();
754 my_req->add_post_wait_work
776template <
typename Context,
typename Iter>
786 typedef typename std::iterator_traits<Iter>::value_type T;
791 std::vector<buffer_t> *
buffer =
new std::vector<buffer_t>();
801 std::numeric_limits<CountType>::max());
804 timpi_error_msg(
"Non-blocking packed range sends cannot exceed " << std::numeric_limits<CountType>::max() <<
"in size");
807 req.add_post_wait_work
819 std::basic_string<T> &
buf,
834 std::basic_string<T> &
buf,
841 std::vector<T> *
tempbuf =
new std::vector<T>(
buf.size());
847 req.add_post_wait_work
849 std::back_insert_iterator<std::basic_string<T>>>
853 req.add_post_wait_work
900 req.add_post_wait_work
906template <
typename T,
typename C,
typename A>
908 std::set<T,C,A> &
buf,
912 (src_processor_id,
buf,
923template <
typename T,
typename C,
typename A>
925 std::set<T,C,A> &
buf,
927 const MessageTag & tag)
const
936template <
typename T,
typename C,
typename A>
938 std::set<T,C,A> &
buf,
939 const DataType & type,
940 const MessageTag & tag)
const
959template <
typename T,
typename C,
typename A>
961 std::set<T,C,A> &
buf,
962 const DataType & type,
964 const MessageTag & tag)
const
970 std::vector<T> *
vecbuf =
new std::vector<T>();
976 req.add_post_wait_work
977 (
new PostWaitCopyBuffer<std::vector<T>,
978 std::insert_iterator<std::set<T,C,A>>>
982 req.add_post_wait_work
983 (
new PostWaitDeleteBuffer<std::vector<T>>(
vecbuf));
991template <
typename T,
typename A>
993 std::vector<T,A> &
buf,
994 const MessageTag & tag)
const
997 (src_processor_id,
buf,
1003template <
typename T,
typename A>
1005 std::vector<T,A> &
buf,
1007 const MessageTag & tag)
const
1015template <
typename T,
typename A>
1017 std::vector<T,A> &
buf,
1018 const DataType & type,
1019 const MessageTag & tag)
const
1025 Status
stat(this->
probe(src_processor_id, tag), type);
1048template <
typename T,
typename A,
1049 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
1051 std::vector<T,A> &
buf,
1052 const DataType & type,
1053 const MessageTag & tag)
const
1062 std::inserter(
buf,
buf.end()),
1070template <
typename T,
typename A,
1071 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
1073 std::vector<T,A> &
buf,
1074 const NotADataType &,
1075 const MessageTag & tag)
const
1084 std::inserter(
buf,
buf.end()),
1092template <
typename T,
typename A>
1094 std::vector<T,A> &
buf,
1095 const DataType & type,
1097 const MessageTag & tag)
const
1110 req.add_post_wait_work
1111 (
new PostWaitDereferenceTag(tag));
1116template <
typename T,
typename A1,
typename A2>
1118 std::vector<std::vector<T,A1>,
A2> &
buf,
1119 const MessageTag & tag)
const
1122 (src_processor_id,
buf,
1129template <
typename T,
typename A1,
typename A2>
1131 std::vector<std::vector<T,A1>,
A2> &
buf,
1133 const MessageTag & tag)
const
1142template <
typename T,
typename A1,
typename A2>
1144 std::vector<std::vector<T,A1>,
A2> & recv,
1145 const DataType & type,
1146 const MessageTag & tag)
const
1150 std::vector<char> recvbuf;
1168 for (std::size_t
i = 0;
i !=
n_vecs; ++
i)
1191template <
typename T,
typename A1,
typename A2>
1193 std::vector<std::vector<T,A1>,
A2> &
buf,
1194 const DataType & type,
1196 const MessageTag & tag)
const
1205 std::vector<char> * recvbuf =
new std::vector<char>(
sendsize);
1211 req.add_post_wait_work
1212 (
new PostWaitUnpackNestedBuffer<std::vector<std::vector<T,A1>,
A2>>
1213 (*recvbuf,
buf, type, *
this));
1216 req.add_post_wait_work
1217 (
new PostWaitDeleteBuffer<std::vector<char>>(recvbuf));
1220 req.add_post_wait_work
1221 (
new PostWaitDereferenceTag(tag));
1225template <
typename Context,
typename OutputIter,
typename T>
1247 std::make_unique<OutputIter>(
out_iter);
1251 std::vector<buffer_t>
buffer;
1289template <
typename Context,
typename OutputIter,
typename T>
1304 std::vector<buffer_t> *
buffer =
new std::vector<buffer_t>(
stat.size());
1308 req.add_post_wait_work
1312 req.add_post_wait_work
1316 req.add_post_wait_work
1322template <
typename T1,
typename T2,
typename A1,
typename A2>
1324 const std::vector<T1,A1> &
sendvec,
1327 std::vector<T2,A2> & recv,
1335 source_processor_id == this->
rank())
1351template <
typename T1,
typename T2,
typename A1,
typename A2,
1352 typename std::enable_if<Has_buffer_type<Packing<T1>>::value &&
1367 (
const T2 *)(
nullptr),
1372template <
typename T,
typename A,
1373 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
1387 (
const T *)(
nullptr),
1393template <
typename T1,
typename T2,
1394 typename std::enable_if<std::is_base_of<DataType, StandardType<T1>>::value &&
1395 std::is_base_of<DataType, StandardType<T2>>::value,
1407 source_processor_id == this->
rank())
1436template <
typename T,
typename A,
1437 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
1440 const std::vector<T,A> &
sendvec,
1442 std::vector<T,A> & recv,
1447 source_processor_id == this->
rank())
1467template <
typename T1,
typename T2,
typename A1,
typename A2,
1468 typename std::enable_if<std::is_base_of<DataType, StandardType<T1>>::value &&
1469 std::is_base_of<DataType, StandardType<T2>>::value,
1472 const std::vector<T1,A1> &
sendvec,
1474 std::vector<T2,A2> & recv,
1490template <
typename T1,
typename T2,
typename A1,
typename A2,
typename A3,
typename A4>
1492 const std::vector<std::vector<T1,A1>,
A2> &
sendvec,
1494 std::vector<std::vector<T2,A3>,
A4> & recv,
1495 const MessageTag & ,
1496 const MessageTag & )
const
1508template <
typename T,
typename A1,
typename A2>
1510 const std::vector<std::vector<T,A1>,
A2> &
sendvec,
1512 std::vector<std::vector<T,A1>,
A2> & recv,
1543 (source_processor_id == this->
rank()));
1545 if (dest_processor_id == this->
rank() &&
1546 source_processor_id == this->
rank())
1555 std::make_unique<OutputIter>(
out_iter);
1560 std::vector<buffer_t>
buffer;
1583template <
typename Context,
typename Iter>
1589 std::shared_ptr<std::vector<
typename Packing<
typename std::iterator_traits<Iter>::value_type>::buffer_type>> &
buffer,
1594 typedef typename std::iterator_traits<Iter>::value_type T;
1600 buffer = std::make_shared<std::vector<buffer_t>>();
1612 std::numeric_limits<CountType>::max());
1615 timpi_error_msg(
"Non-blocking packed range sends cannot exceed " << std::numeric_limits<CountType>::max() <<
"in size");
1618 req.add_post_wait_work
1628template <
typename T,
typename A>
1630 std::vector<std::basic_string<T>,
A> & recv,
1636 recv.assign(this->
size(),
"");
1639 if (this->
size() < 2)
1646 std::vector<CountType>
1648 std::vector<DispType>
1662 for (
unsigned int i=0;
i != this->
size(); ++
i)
1683 for (
unsigned int i=0;
i != this->
size(); ++
i)
1693 if (this->
size() == 1)
1719template <
typename T>
1724 if (this->
size() == 1)
1748 if (this->
rank() == root_id)
1749 for (std::size_t
i=0;
i<
data.size();
i++)
1757 if (this->
rank() == root_id)
1763template <
typename T,
typename A>
1768 if (this->
size() == 1)
1783 for (std::size_t
i=0;
i<
data.size(); ++
i)
1797 for (std::size_t
i=0;
i<
data.size(); ++
i)
1800 for (std::size_t
j=0;
j !=
data[
i].size(); ++
j)
1818 typename std::vector<unsigned int>::const_iterator
iter =
temp.begin();
1830template <
typename T,
typename A1,
typename A2>
1835 if (this->
size() == 1)
1886 typename std::vector<T>::const_iterator
iter =
temp.begin();
1898template <
typename T,
typename C,
typename A>
1903 if (this->
size() == 1)
1916 if (this->
rank() == root_id)
1924 if (this->
rank() != root_id)
1928 if (this->
rank() != root_id)
1936template <
typename Context,
typename OutputIter,
typename T>
1948 buffer = std::make_shared<std::vector<typename Packing<T>::buffer_type>>();
1960 req.add_post_wait_work
1964 req.add_post_wait_work
1970template <
typename T,
typename A,
typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
1972 std::vector<T,A> &
buf,
2004 req.add_post_wait_work
2011template <
typename T,
typename A,
typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
2013 std::vector<T,A> &
buf,
2022 std::inserter(
buf,
buf.end()),
2030template <
typename T,
typename A1,
typename A2>
2032 std::vector<std::vector<T,A1>,
A2> &
buf,
2056 std::vector<char> * recvbuf =
2062 req.add_post_wait_work
2064 (*recvbuf,
buf, type, *
this));
2067 req.add_post_wait_work
2071 req.add_post_wait_work
2091template <
typename T>
2101 this->
min(verified);
2106 "Tried to verify an unverifiable type");
2111template <
typename T>
2133 "Tried to semiverify an unverifiable type");
2140template <
typename T,
typename A>
2145 std::size_t
rsize =
r ?
r->size() : 0;
2174 "Tried to semiverify a vector of an unverifiable type");
2181template <
typename A>
2184 if (this->
size() > 1 && !r.empty())
2190 std::vector<unsigned int>
ruint;
2192 std::vector<unsigned int>
temp(
ruint.size());
2203template <
typename T>
2205 unsigned int &
min_id)
const
2207 if (this->
size() > 1)
2228template <
typename T,
typename A1,
typename A2>
2230 std::vector<unsigned int,A2> &
min_id)
const
2232 if (this->
size() > 1 && !r.empty())
2238 std::vector<DataPlusInt<T>>
data_in(
r.size());
2239 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2244 std::vector<DataPlusInt<T>>
data_out(
r.size());
2251 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2257 else if (!
r.empty())
2259 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2265template <
typename A1,
typename A2>
2267 std::vector<unsigned int,A2> &
min_id)
const
2269 if (this->
size() > 1 && !r.empty())
2275 std::vector<DataPlusInt<int>>
data_in(
r.size());
2276 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2281 std::vector<DataPlusInt<int>>
data_out(
r.size());
2287 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2293 else if (!
r.empty())
2295 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2302template <
typename A>
2305 if (this->
size() > 1 && !r.empty())
2311 std::vector<unsigned int>
ruint;
2313 std::vector<unsigned int>
temp(
ruint.size());
2325template <
typename Map,
2326 typename std::enable_if<std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
2327 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value,
2331 if (this->
size() > 1)
2341 std::vector<std::pair<typename Map::key_type, typename Map::mapped_type>>
2360 it->second = std::max(
it->second,
pr.second);
2368template <
typename Map,
2369 typename std::enable_if<!(std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
2370 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value),
2374 if (this->size() > 1)
2384 std::vector<typename Map::key_type>
keys;
2385 std::vector<typename Map::mapped_type>
vals;
2391 for (
const auto &
pr :
data)
2393 keys.push_back(
pr.first);
2394 vals.push_back(
pr.second);
2397 this->allgather(
keys,
false);
2398 this->allgather(
vals,
false);
2402 for (std::size_t
i=0;
i<
keys.size(); ++
i)
2414 it->second = std::max(
it->second,
vals[
i]);
2422template <
typename K,
typename V,
typename C,
typename A>
2431template <
typename K,
typename V,
typename H,
typename E,
typename A>
2440template <
typename T>
2442 unsigned int &
max_id)
const
2444 if (this->
size() > 1)
2465template <
typename T,
typename A1,
typename A2>
2467 std::vector<unsigned int,A2> &
max_id)
const
2469 if (this->
size() > 1 && !r.empty())
2475 std::vector<DataPlusInt<T>>
data_in(
r.size());
2476 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2481 std::vector<DataPlusInt<T>>
data_out(
r.size());
2489 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2495 else if (!
r.empty())
2497 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2503template <
typename A1,
typename A2>
2505 std::vector<unsigned int,A2> &
max_id)
const
2507 if (this->
size() > 1 && !r.empty())
2513 std::vector<DataPlusInt<int>>
data_in(
r.size());
2514 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2519 std::vector<DataPlusInt<int>>
data_out(
r.size());
2526 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2532 else if (!
r.empty())
2534 for (std::size_t
i=0;
i !=
r.size(); ++
i)
2539#define TIMPI_DEFINE_COMMUNICATOR_OPS(OPNAME) \
2540 template <typename T> \
2541 inline void Communicator::OPNAME(T &timpi_mpi_var(r)) const { \
2542 if (this->size() > 1) { \
2543 TIMPI_LOG_SCOPE(#OPNAME "(scalar, blocking)", "Parallel"); \
2545 timpi_call_mpi(TIMPI_ALLREDUCE(MPI_IN_PLACE, &r, 1, StandardType<T>(&r), \
2546 OpFunction<T>::OPNAME(), this->get())); \
2550 template <typename T, typename A> \
2551 inline void Communicator::OPNAME(std::vector<T, A> &r) const { \
2552 if (this->size() > 1 && !r.empty()) { \
2553 TIMPI_LOG_SCOPE(#OPNAME "(vector, blocking)", "Parallel"); \
2555 timpi_assert(this->verify(r.size())); \
2557 timpi_call_mpi(TIMPI_ALLREDUCE( \
2558 MPI_IN_PLACE, r.data(), cast_int<CountType>(r.size()), \
2559 StandardType<T>(r.data()), OpFunction<T>::OPNAME(), this->get())); \
2562 template <typename T> \
2563 inline void Communicator::OPNAME(const T &r, T &o, Request &req) const { \
2564 if (this->size() > 1) { \
2565 TIMPI_LOG_SCOPE(#OPNAME "(scalar, nonblocking)", "Parallel"); \
2567 timpi_call_mpi(TIMPI_IALLREDUCE(&r, &o, 1, StandardType<T>(&r), \
2568 OpFunction<T>::OPNAME(), this->get(), \
2572 req = Request::null_request; \
2591template <
typename T>
2594 if (this->
size() > 1)
2607template <
typename T,
typename A>
2610 if (this->
size() > 1 && !r.empty())
2620 OpFunction<T>::sum(),
this->get()));
2628template <
typename Map,
2629 typename std::enable_if<std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
2630 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value,
2634 if (this->
size() > 1)
2645 std::vector<std::pair<typename Map::key_type, typename Map::mapped_type>>
2660template <
typename Map,
2661 typename std::enable_if<!(std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
2662 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value),
2666 if (this->size() > 1)
2673 std::vector<typename Map::key_type>
keys;
2674 std::vector<typename Map::mapped_type>
vals;
2680 for (
const auto &
pr :
data)
2682 keys.push_back(
pr.first);
2683 vals.push_back(
pr.second);
2686 this->allgather(
keys,
false);
2687 this->allgather(
vals,
false);
2691 for (std::size_t
i=0;
i<
keys.size(); ++
i)
2698template <
typename K,
typename V,
typename C,
typename A>
2706template <
typename K,
typename V,
typename H,
typename E,
typename A>
2714template <
typename T,
typename A1,
typename A2,
2715 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
2717 std::vector<std::vector<T,A1>,
A2> & recv,
2725 if (this->
size() < 2)
2733 recv.resize(this->
size());
2735 std::vector<CountType>
2737 std::vector<DispType>
2751 for (
unsigned int i=0;
i != this->
size(); ++
i)
2767 mysize, StandardType<T>(),
2769 StandardType<T>(),
this->
get()));
2772 for (
unsigned int i=0;
i != this->
size(); ++
i)
2779template <
typename T,
typename A1,
typename A2,
2780 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
2782 std::vector<std::vector<T,A1>,
A2> & recv,
2787 typedef typename Packing<T>::buffer_type
buffer_t;
2789 std::vector<buffer_t>
buffer;
2792 std::numeric_limits<CountType>::max());
2795 timpi_error_msg(
"Non-blocking packed range sends cannot exceed " << std::numeric_limits<CountType>::max() <<
"in size");
2797 std::vector<std::vector<buffer_t>>
allbuffers;
2801 recv.resize(this->
size());
2809 std::back_inserter(recv[
i]), (T*)
nullptr);
2814template <
typename T,
typename C,
typename A>
2816 const unsigned int root_id)
const
2818 if (this->
size() > 1)
2822 if (this->
rank() == root_id)
2829template <
typename T,
typename C,
typename A>
2832 if (this->
size() > 1)
2842template <
typename T,
typename C,
typename A>
2844 const unsigned int root_id)
const
2846 if (this->
size() > 1)
2850 if (this->
rank() == root_id)
2860template <
typename T,
typename C,
typename A>
2863 if (this->
size() > 1)
2877template <
typename T1,
typename T2,
typename C,
typename A>
2879 const unsigned int root_id)
const
2881 if (this->
size() > 1)
2886 if (this->
rank() == root_id)
2900template <
typename T1,
typename T2,
typename C,
typename A>
2903 if (this->
size() > 1)
2918template <
typename T1,
typename T2,
typename C,
typename A>
2920 const unsigned int root_id)
const
2922 if (this->
size() > 1)
2927 if (this->
rank() == root_id)
2939template <
typename T1,
typename T2,
typename C,
typename A>
2942 if (this->
size() > 1)
2956template <
typename K,
typename H,
typename KE,
typename A>
2958 const unsigned int root_id)
const
2960 if (this->
size() > 1)
2964 if (this->
rank() == root_id)
2971template <
typename K,
typename H,
typename KE,
typename A>
2974 if (this->
size() > 1)
2984template <
typename K,
typename H,
typename KE,
typename A>
2986 const unsigned int root_id)
const
2988 if (this->
size() > 1)
2992 if (this->
rank() == root_id)
3004template <
typename K,
typename H,
typename KE,
typename A>
3007 if (this->
size() > 1)
3021template <
typename K,
typename T,
typename H,
typename KE,
typename A>
3023 const unsigned int root_id)
const
3025 if (this->
size() > 1)
3030 if (this->
rank() == root_id)
3044template <
typename K,
typename T,
typename H,
typename KE,
typename A>
3047 if (this->
size() > 1)
3062template <
typename K,
typename T,
typename H,
typename KE,
typename A>
3064 const unsigned int root_id)
const
3066 if (this->
size() > 1)
3071 if (this->
rank() == root_id)
3083template <
typename K,
typename T,
typename H,
typename KE,
typename A>
3086 if (this->
size() > 1)
3100template <
typename T,
typename A>
3103 std::vector<T,A> & recv)
const
3107 if (this->
rank() == root_id)
3108 recv.resize(this->
size());
3110 if (this->
size() > 1)
3129template <
typename T,
typename A,
3130 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
3132 std::vector<T,A> &
r)
const
3134 if (this->
size() == 1)
3143 std::vector<CountType>
3145 std::vector<DispType>
3156 for (
unsigned int i=0;
i != this->
size(); ++
i)
3167 std::vector<T,A>
r_src(
r);
3185template <
typename T,
typename A,
3186 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
3188 std::vector<T,A> &
r)
const
3200template <
typename T,
typename A>
3202 const std::basic_string<T> &
sendval,
3203 std::vector<std::basic_string<T>,
A> & recv,
3208 if (this->
rank() == root_id)
3209 recv.resize(this->
size());
3211 if (this->
size() > 1)
3215 std::vector<CountType>
3217 std::vector<DispType>
3231 for (
unsigned int i=0;
i < this->
size(); ++
i)
3238 std::basic_string<T>
r;
3253 if (this->
rank() == root_id)
3254 for (
unsigned int i=0;
i != this->
size(); ++
i)
3263template <
typename T,
typename A,
3264 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
3266 std::vector<T,A> & recv)
const
3271 recv.resize(this->
size());
3286template <
typename T,
typename A,
3287 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
3289 std::vector<T,A> & recv)
const
3294 recv.resize(this->
size());
3300 unsigned int comm_size = this->
size();
3312template <
typename T,
typename A,
3313 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
3317 if (this->
size() < 2)
3322 if (identical_buffer_sizes)
3328 std::vector<T,A>
r_src(
r.size()*
this->size());
3340 std::vector<CountType>
3342 std::vector<DispType>
3351 for (
unsigned int i=0;
i != this->
size(); ++
i)
3375template <
typename T,
typename A,
3376 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
3380 if (this->
size() < 2)
3385 if (identical_buffer_sizes)
3392 std::vector<T,A>
r_src(
r.size()*
this->size());
3402 std::vector<CountType>
3404 std::vector<DispType>
3412 for (
unsigned int i=0;
i != this->
size(); ++
i)
3429template <
typename T,
typename A>
3433 if (this->
size() < 2)
3438 if (identical_buffer_sizes)
3454 for (std::size_t
i=0;
i !=
r.size(); ++
i)
3461 for (std::size_t
i=0;
i !=
r.size(); ++
i)
3480 for (
unsigned int i=0;
i != this->
size(); ++
i)
3506 for (std::size_t
i=0;
i !=
r.size(); ++
i)
3516template <
typename T,
typename A>
3519 const unsigned int root_id)
const
3528 if (this->
size() == 1)
3550template <
typename T,
typename A>
3552 std::vector<T,A> & recv,
3553 const unsigned int root_id)
const
3557 if (this->
size() == 1)
3561 recv.assign(
data.begin(),
data.end());
3568 if (this->
rank() == root_id)
3591template <
typename T,
typename A1,
typename A2>
3593 const std::vector<CountType,A2>
counts,
3594 std::vector<T,A1> & recv,
3595 const unsigned int root_id)
const
3599 if (this->
size() == 1)
3609 if (root_id == this->
rank())
3615 for (
unsigned int i=0;
i < this->
size(); ++
i)
3645#ifdef TIMPI_HAVE_MPI
3650template <
typename T,
typename A1,
typename A2>
3652 const std::vector<int,A2>
counts,
3653 std::vector<T,A1> & recv,
3654 const unsigned int root_id)
const
3664template <
typename T,
typename A1,
typename A2>
3666 std::vector<T,A1> & recv,
3672 if (this->
size() == 1)
3682 std::vector<CountType>
counts;
3691 for (std::size_t
i=0;
i <
data.size(); ++
i)
3712template <
typename T,
typename A>
3715 if (this->
size() < 2 || buf.empty())
3741#ifdef TIMPI_HAVE_MPI
3743 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type
3751 if (this->
size() == 1)
3768#ifdef TIMPI_HAVE_MPI
3769template <
typename T,
3770 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
3776 if (this->
size() == 1)
3805template <
typename T,
typename A,
3806 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
3812 if (this->
size() == 1)
3819#ifdef TIMPI_HAVE_MPI
3847template <
typename T,
typename A,
3848 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
3853 if (this->
size() == 1)
3884template <
typename Map,
3885 typename std::enable_if<std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
3886 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value,
3893 if (this->
size() == 1)
3900#ifdef TIMPI_HAVE_MPI
3912 std::vector<std::pair<
typename Map::key_type,
3916 comm_data.assign(
data.begin(),
data.end());
3922 if (this->
rank() != root_id)
3930template <
typename Map,
3931 typename std::enable_if<!(std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
3932 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value),
3939 if (this->size() == 1)
3946#ifdef TIMPI_HAVE_MPI
3963 for (
const auto &
pr :
data)
3993template <
typename T1,
typename T2,
typename C,
typename A>
4003template <
typename K,
typename V,
typename H,
typename E,
typename A>
4021 typedef typename std::iterator_traits<Iter>::value_type T;
4022 typedef typename Packing<T>::buffer_type
buffer_t;
4024 if (this->
size() == 1)
4035 std::vector<buffer_t>
buffer;
4037 if (this->
rank() == root_id)
4058 std::make_unique<OutputIter>(
out_iter);
4060 if (this->
rank() != root_id)
4070template <
typename Context,
typename Iter,
typename OutputIter>
4078 typedef typename std::iterator_traits<Iter>::value_type T;
4079 typedef typename Packing<T>::buffer_type
buffer_t;
4082 this->
max(nonempty_range);
4087 std::make_unique<OutputIter>(
out_iter);
4093 std::vector<buffer_t>
buffer;
4105 this->
max(nonempty_range);
4110template <
typename Context,
typename Iter,
typename OutputIter>
4117 typedef typename std::iterator_traits<Iter>::value_type T;
4118 typedef typename Packing<T>::buffer_type
buffer_t;
4121 this->
max(nonempty_range);
4126 std::make_unique<OutputIter>(
out_iter);
4132 std::vector<buffer_t>
buffer;
4146 this->
max(nonempty_range);
4154 const MessageTag & tag,
4161 Status
stat((StandardType<
typename Packing<T>::buffer_type>()));
4181template <
typename T,
typename A,
4182 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type>
4184 std::vector<T,A> &
buf,
4186 const MessageTag & tag)
const
4193template <
typename T,
typename A,
4194 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type>
4196 std::vector<T,A> &
buf,
4198 const MessageTag & tag)
const
4210template <
typename T,
typename A1,
typename A2>
4212 std::vector<std::vector<T,A1>,
A2> &
buf,
4214 const MessageTag & tag)
const
4222template <
typename Context,
typename OutputIter,
typename T>
4228 const MessageTag & tag)
const
4249 req.add_post_wait_work
4250 (
new PostWaitDereferenceTag(tag));
Encapsulates the MPI_Comm object.
void max(const T &r, T &o, Request &req) const
Non-blocking maximum of the local value r into o with the request req.
bool possibly_receive_packed_range(unsigned int &src_processor_id, Context *context, OutputIter out, const T *output_type, Request &req, const MessageTag &tag) const
Nonblocking packed range receive from one processor with user-defined type.
void nonblocking_receive_packed_range(const unsigned int src_processor_id, Context *context, OutputIter out, const T *output_type, Request &req, Status &stat, const MessageTag &tag=any_tag) const
Non-Blocking-receive range-of-pointers from one processor.
void allgather_packed_range(Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
Take a range of local variables, combine it with ranges from all processors, and write the output to ...
SendMode send_mode() const
Gets the user-requested SendMode.
processor_id_type size() const
std::size_t packed_size_of(const std::vector< std::vector< T, A1 >, A2 > &buf, const DataType &type) const
void broadcast_packed_range(const Context *context1, Iter range_begin, const Iter range_end, OutputContext *context2, OutputIter out, const unsigned int root_id=0, std::size_t approx_buffer_size=1000000) const
Blocking-broadcast range-of-pointers to one processor.
void maxloc(T &r, unsigned int &max_id) const
Take a local variable and replace it with the maximum of it's values on all processors,...
void receive_packed_range(const unsigned int dest_processor_id, Context *context, OutputIter out, const T *output_type, const MessageTag &tag=any_tag) const
Blocking-receive range-of-pointers from one processor.
Status packed_range_probe(const unsigned int src_processor_id, const MessageTag &tag, bool &flag) const
Non-Blocking message probe for a packed range message.
void nonblocking_send_packed_range(const unsigned int dest_processor_id, const Context *context, Iter range_begin, const Iter range_end, Request &req, const MessageTag &tag=no_tag) const
Similar to the above Nonblocking send_packed_range with a few important differences:
status probe(const unsigned int src_processor_id, const MessageTag &tag=any_tag) const
Blocking message probe.
void map_broadcast(Map &data, const unsigned int root_id, const bool identical_sizes) const
Private implementation function called by the map-based broadcast() specializations.
processor_id_type rank() const
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
Blocking-receive from one processor with data-defined type.
void map_max(Map &data) const
Private implementation function called by the map-based max() specializations.
void alltoall(std::vector< T, A > &r) const
Effectively transposes the input vector across all processors.
timpi_pure bool semiverify(const T *r) const
Check whether a local pointer points to the same value on all processors where it is not null,...
void map_sum(Map &data) const
Private implementation function called by the map-based sum() specializations.
void min(const T &r, T &o, Request &req) const
Non-blocking minimum of the local value r into o with the request req.
timpi_pure bool verify(const T &r) const
Check whether a local variable has the same value on all processors, returning true if it does or fal...
void minloc(T &r, unsigned int &min_id) const
Take a local variable and replace it with the minimum of it's values on all processors,...
void sum(T &r) const
Take a local variable and replace it with the sum of it's values on all processors.
void send_receive(const unsigned int dest_processor_id, const T1 &send_data, const unsigned int source_processor_id, T2 &recv_data, const MessageTag &send_tag=no_tag, const MessageTag &recv_tag=any_tag) const
Send data send to one processor while simultaneously receiving other data recv from a (potentially di...
void set_union(T &data, const unsigned int root_id) const
Take a container (set, map, unordered_set, multimap, etc) of local variables on each processor,...
void gather_packed_range(const unsigned int root_id, Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
Take a range of local variables, combine it with ranges from all processors, and write the output to ...
void scatter(const std::vector< T, A > &data, T &recv, const unsigned int root_id=0) const
Take a vector of local variables and scatter the ith item to the ith processor in the communicator.
bool possibly_receive(unsigned int &src_processor_id, std::vector< T, A > &buf, Request &req, const MessageTag &tag) const
Nonblocking-receive from one processor with user-defined type.
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
Take a local value and broadcast it to all processors.
void assign(const communicator &comm)
Utility function for setting our member variables from an MPI communicator.
void send_packed_range(const unsigned int dest_processor_id, const Context *context, Iter range_begin, const Iter range_end, const MessageTag &tag=no_tag, std::size_t approx_buffer_size=1000000) const
Blocking-send range-of-pointers to one processor.
void gather(const unsigned int root_id, const T &send_data, std::vector< T, A > &recv) const
Take a vector of length comm.size(), and on processor root_id fill in recv[processor_id] = the value ...
void send_receive_packed_range(const unsigned int dest_processor_id, const Context1 *context1, RangeIter send_begin, const RangeIter send_end, const unsigned int source_processor_id, Context2 *context2, OutputIter out, const T *output_type, const MessageTag &send_tag=no_tag, const MessageTag &recv_tag=any_tag, std::size_t approx_buffer_size=1000000) const
Send a range-of-pointers to one processor while simultaneously receiving another range from a (potent...
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
Take a vector of length this->size(), and fill in recv[processor_id] = the value of send on that proc...
void send(const unsigned int dest_processor_id, const T &buf, const MessageTag &tag=no_tag) const
Blocking-send to one processor with data-defined type.
Types combined with an int.
Encapsulates the MPI_Datatype.
Encapsulates the MPI tag integers.
StandardType<T>'s which do not define a way to MPI_Type T should inherit from this class.
static const bool is_fixed_type
Templated class to provide the appropriate MPI reduction operations for use with built-in C types or ...
Encapsulates the MPI_Request.
Templated class to provide the appropriate MPI datatype for use with built-in C types or simple C++ c...
Encapsulates the MPI_Status struct.
Define data types and (un)serialization functions for use when encoding a potentially-variable-size o...
const MessageTag any_tag
Default message tag ids.
data_type dataplusint_type< float >()
data_type dataplusint_type< double >()
MPI_Request request
Request object for non-blocking I/O.
data_type dataplusint_type< long >()
Iter pack_range(const Context *context, Iter range_begin, const Iter range_end, std::vector< buffertype > &buffer, std::size_t approx_buffer_size)
Helper function for range packing.
uint8_t processor_id_type
data_type dataplusint_type< int >()
const unsigned int any_source
Processor id meaning "Accept from any source".
Tnew cast_int(Told oldvar)
data_type dataplusint_type< long double >()
std::pair< data_type, std::unique_ptr< StandardType< std::pair< T, int > > > > dataplusint_type_acquire()
std::size_t packed_range_size(const Context *context, Iter range_begin, const Iter range_end)
Helper function for range packing.
OutputIter unpack_range(const std::vector< buffertype > &buffer, Context *context, OutputIter out_iter, const T *)
Helper function for range unpacking.
void ignore(const Args &...)
data_type dataplusint_type()
Templated function to return the appropriate MPI datatype for use with built-in C types when combined...
data_type dataplusint_type< short int >()
static const bool has_min_max