506 const U& x, std::array<std::int64_t, 2> shape,
507 std::int64_t rank_offset)
509 assert(rank_offset >= 0 or x.empty());
510 using T = std::ranges::range_value_t<U>;
513 assert(shape[1] > 0);
517 assert(x.size() % shape[1] == 0);
518 const std::int64_t shape0_local = x.size() / shape[1];
526 auto [send_dest, num_items_per_send_dest, pos_to_neigh_rank]
527 = impl::postoffice_plan(
size,
rank, shape0_local, shape[0], rank_offset);
532 std::vector<std::tuple<int, std::int64_t, std::int32_t>> src_to_index;
533 for (std::size_t i = 0; i < indices.size(); ++i)
535 std::int64_t idx = indices[i];
536 if (idx >= rank_offset and idx < rank_offset + shape0_local)
539 src_to_index.push_back({src, idx, i});
545 std::vector<std::int32_t> perm(src_to_index.size());
546 std::iota(perm.begin(), perm.end(), 0);
548 {
return std::get<0>(src_to_index[i]); });
549 std::vector<std::tuple<int, std::int64_t, std::int32_t>> sorted(
550 src_to_index.size());
551 for (std::size_t i = 0; i < perm.size(); ++i)
552 sorted[i] = src_to_index[perm[i]];
553 src_to_index = std::move(sorted);
558 std::vector<std::int32_t> num_items_per_src;
559 std::vector<int> src;
561 auto it = src_to_index.begin();
562 while (it != src_to_index.end())
564 src.push_back(std::get<0>(*it));
565 auto it1 = std::ranges::find_if(it, src_to_index.end(),
566 [r = src.back()](
auto& idx)
567 { return std::get<0>(idx) != r; });
568 num_items_per_src.push_back(std::ranges::distance(it, it1));
578 comm, send_dest,
static_cast<int>(tag::consensus_nbx), src,
579 static_cast<int>(tag::consensus_nbx) + 1);
581 "Neighbourhood destination ranks from post office in "
582 "distribute_data (rank, num dests, num dests/mpi_size): {}, {}, {}",
583 rank, dest.size(),
static_cast<double>(dest.size()) /
size);
587 auto [post_indices, post_x] = impl::postoffice_exchange(
588 comm, x, {shape[0], shape[1]}, rank_offset, send_dest,
589 num_items_per_send_dest, pos_to_neigh_rank, post_src);
590 assert(post_indices.size() == post_x.size() / shape[1]);
594 MPI_Comm neigh_comm0;
595 int err = MPI_Dist_graph_create_adjacent(
596 comm, dest.size(), dest.data(), MPI_UNWEIGHTED, src.size(), src.data(),
597 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &neigh_comm0);
601 std::vector<int> num_items_recv(dest.size());
602 num_items_per_src.reserve(1);
603 num_items_recv.reserve(1);
604 err = MPI_Neighbor_alltoall(num_items_per_src.data(), 1, MPI_INT,
605 num_items_recv.data(), 1, MPI_INT, neigh_comm0);
609 std::vector<std::int32_t> send_disp{0};
610 std::partial_sum(num_items_per_src.begin(), num_items_per_src.end(),
611 std::back_inserter(send_disp));
612 std::vector<std::int32_t> recv_disp = {0};
613 std::partial_sum(num_items_recv.begin(), num_items_recv.end(),
614 std::back_inserter(recv_disp));
618 assert(send_disp.back() ==
static_cast<int>(src_to_index.size()));
619 std::vector<std::int64_t> send_buffer_index(src_to_index.size());
620 std::ranges::transform(src_to_index, send_buffer_index.begin(),
621 [](
auto x) { return std::get<1>(x); });
624 std::vector<std::int64_t> recv_buffer_index(recv_disp.back());
625 err = MPI_Neighbor_alltoallv(
626 send_buffer_index.data(), num_items_per_src.data(), send_disp.data(),
627 MPI_INT64_T, recv_buffer_index.data(), num_items_recv.data(),
628 recv_disp.data(), MPI_INT64_T, neigh_comm0);
631 err = MPI_Comm_free(&neigh_comm0);
640 const std::array<std::int64_t, 2> postoffice_range
642 std::vector<std::int32_t> post_indices_map(
643 postoffice_range[1] - postoffice_range[0], -1);
644 for (std::size_t i = 0; i < post_indices.size(); ++i)
646 assert(post_indices[i] <
static_cast<int>(post_indices_map.size()));
647 post_indices_map[post_indices[i]] = i;
651 std::vector<T> send_buffer_data(shape[1] * recv_disp.back());
652 for (std::int32_t i = 0; i < recv_disp.back(); ++i)
654 std::int64_t index = recv_buffer_index[i];
655 if (index >= rank_offset and index < (rank_offset + shape0_local))
658 std::int32_t local_index = index - rank_offset;
659 std::copy_n(std::next(x.begin(), shape[1] * local_index), shape[1],
660 std::next(send_buffer_data.begin(), shape[1] * i));
665 std::int64_t local_index = index - postoffice_range[0];
666 std::int32_t pos = post_indices_map[local_index];
668 std::copy_n(std::next(post_x.begin(), shape[1] * pos), shape[1],
669 std::next(send_buffer_data.begin(), shape[1] * i));
673 err = MPI_Dist_graph_create_adjacent(
674 comm, src.size(), src.data(), MPI_UNWEIGHTED, dest.size(), dest.data(),
675 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &neigh_comm0);
678 MPI_Datatype compound_type0;
680 MPI_Type_commit(&compound_type0);
682 std::vector<T> recv_buffer_data(shape[1] * send_disp.back());
683 err = MPI_Neighbor_alltoallv(
684 send_buffer_data.data(), num_items_recv.data(), recv_disp.data(),
685 compound_type0, recv_buffer_data.data(), num_items_per_src.data(),
686 send_disp.data(), compound_type0, neigh_comm0);
689 err = MPI_Type_free(&compound_type0);
691 err = MPI_Comm_free(&neigh_comm0);
694 std::vector<std::int32_t> index_pos_to_buffer(indices.size(), -1);
695 for (std::size_t i = 0; i < src_to_index.size(); ++i)
696 index_pos_to_buffer[std::get<2>(src_to_index[i])] = i;
699 std::vector<T> x_new(shape[1] * indices.size());
700 for (std::size_t i = 0; i < indices.size(); ++i)
702 const std::int64_t index = indices[i];
703 if (index >= rank_offset and index < (rank_offset + shape0_local))
706 std::int64_t local_index = index - rank_offset;
707 std::copy_n(std::next(x.begin(), shape[1] * local_index), shape[1],
708 std::next(x_new.begin(), shape[1] * i));
710 else if (std::int32_t pos = index_pos_to_buffer[i]; pos != -1)
715 std::copy_n(std::next(recv_buffer_data.begin(), shape[1] * pos), shape[1],
716 std::next(x_new.begin(), shape[1] * i));
721 std::int64_t local_index = index - postoffice_range[0];
722 std::int32_t bag_pos = post_indices_map[local_index];
723 assert(bag_pos != -1);
724 std::copy_n(std::next(post_x.begin(), shape[1] * bag_pos), shape[1],
725 std::next(x_new.begin(), shape[1] * i));