1#ifndef MPI_COMMUNICATOR_H
2#define MPI_COMMUNICATOR_H
13 template <
typename GeneType>
16 static constexpr int MPI_MESSAGE_TAG = 99;
18 static constexpr std::size_t RECEIVE_BUFFER_OVERHEAD = 1024;
21 std::vector<uint8_t> receive_buffer_m;
26 std::size_t network_size_m;
28 bool is_running_m =
false;
29 MPI_Request mpi_request_m = MPI_REQUEST_NULL;
33 const std::size_t max_payload_size,
34 const MPI_Comm comm = MPI_COMM_WORLD)
35 : serializer_m(serializer), comm_m(comm) {
37 MPI_Initialized(&initialized);
39 throw std::runtime_error(
"MPI must be initialized before creating MpiCommunicator");
42 receive_buffer_m.resize(max_payload_size + RECEIVE_BUFFER_OVERHEAD);
46 MPI_Comm_rank(comm_m, &rank);
47 MPI_Comm_size(comm_m, &network_size);
50 network_size_m =
static_cast<std::size_t
>(network_size);
60 migration_buffer_m = &target_buffer;
63 receive_buffer_m.data(),
64 static_cast<int>(receive_buffer_m.size()),
76 if (!is_running_m)
return;
89 if (!is_received)
break;
91 int received_bytes_count;
99 std::vector<Individual<GeneType>> migrants = serializer_m.
deserialize(
100 receive_buffer_m.data(),
101 static_cast<std::size_t
>(received_bytes_count)
104 migration_buffer_m->
push(std::move(migrants));
107 receive_buffer_m.data(),
108 static_cast<int>(receive_buffer_m.size()),
119 if (!is_running_m)
return;
121 is_running_m =
false;
123 if (mpi_request_m != MPI_REQUEST_NULL) {
124 MPI_Cancel(&mpi_request_m);
127 MPI_Wait(&mpi_request_m, &status);
129 mpi_request_m = MPI_REQUEST_NULL;
134 const std::vector<std::uint8_t> serialized_data = serializer_m.
serialize(deme);
137 serialized_data.data(),
138 static_cast<int>(serialized_data.size()),
140 static_cast<int>(destination_rank),
147 const std::vector<std::size_t>& destination_ranks)
override {
148 if (destination_ranks.empty())
return;
150 const std::vector<std::uint8_t> serialized_data = serializer_m.
serialize(deme);
152 for (
const auto& destination_rank : destination_ranks) {
154 serialized_data.data(),
155 static_cast<int>(serialized_data.size()),
157 static_cast<int>(destination_rank),
170 const DoubleInt local_best{individual.
getFitness(), rank_m};
171 DoubleInt global_best;
182 std::vector<std::uint8_t> buffer;
185 if (rank_m == global_best.rank) {
186 buffer = std::move(serializer_m.
serialize(individual));
187 buffer_size =
static_cast<int>(buffer.size());
198 if (buffer_size > 0) {
199 if (rank_m != global_best.rank) {
200 buffer.resize(buffer_size);
212 if (rank_m == global_best.rank) {
return individual; }
214 auto deserialized = serializer_m.
deserialize(buffer);
215 if (deserialized.empty()) {
216 return std::move(individual);
219 return std::move(deserialized[0]);
223 [[nodiscard]] std::size_t
getRank()
const override {
227 [[nodiscard]] std::size_t
getSize()
const override {
228 return network_size_m;
Represents a single candidate solution in the population.
double getFitness() const
Gets the current fitness score.
Interface for network communication between islands.
Interface for a thread-safe buffer that stores incoming migrants.
virtual void push(std::vector< Individual< GeneType > > &&incoming_deme_batch)=0
Adds a batch of individuals to the buffer.
MpiCommunicator(Serializer< GeneType > &serializer, const std::size_t max_payload_size, const MPI_Comm comm=MPI_COMM_WORLD)
Individual< GeneType > allReduceBest(Individual< GeneType > individual) const override
Global reduction to find the best individual across all islands.
void broadcast(const std::vector< Individual< GeneType > > &deme, const std::vector< std::size_t > &destination_ranks) override
Sends a deme to multiple destination islands.
std::size_t getRank() const override
Gets the network rank of the local node.
void update() override
Processes any pending network events (e.g. polls for incoming messages).
void send(const std::vector< Individual< GeneType > > &deme, const std::size_t destination_rank) override
Sends a deme to a specific destination island.
std::size_t getSize() const override
Gets the total number of islands in the network.
void startReceiving(MigrationBuffer< GeneType > &target_buffer) override
Begins asynchronous background receiving of migrants.
void stopReceiving() override
Stops background communication activities.
Interface for converting individuals to/from byte streams for network transport.
virtual std::vector< std::uint8_t > serialize(const std::vector< Individual< GeneType > > &individuals) const =0
Serializes multiple individuals into a byte vector.
virtual std::vector< Individual< GeneType > > deserialize(const std::vector< std::uint8_t > &individuals_serialized) const =0
Deserializes a byte vector into individuals.