This commit is contained in:
Eremey Valetov 2026-03-01 00:55:29 +00:00 committed by GitHub
commit 692225bdbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 819 additions and 167 deletions

View file

@ -42,6 +42,12 @@
* Abstract class for multi-objective algorithms. * Abstract class for multi-objective algorithms.
*/ */
class moeoAlgo class moeoAlgo
{}; {
public:
virtual ~moeoAlgo() = default;
/** Whether this algorithm supports finalize() for post-integration updates. */
virtual bool hasFinalize() const { return false; }
};
#endif /*MOEOALGO_H_*/ #endif /*MOEOALGO_H_*/

View file

@ -148,6 +148,17 @@ public:
while (continuator (_pop)); while (continuator (_pop));
} }
/**
* Recompute fitness and diversity assignments on the population.
* Useful after integrating immigrants from an island model.
* @param _pop the population to finalize
*/
void finalize(eoPop<MOEOT>& _pop) override {
fitnessAssignment(_pop);
diversityAssignment(_pop);
}
bool hasFinalize() const override { return true; }
protected: protected:

View file

@ -47,6 +47,14 @@
*/ */
template < class MOEOT > template < class MOEOT >
class moeoPopAlgo : public moeoAlgo, public eoAlgo < MOEOT > class moeoPopAlgo : public moeoAlgo, public eoAlgo < MOEOT >
{}; {
public:
/**
* Recompute fitness/diversity after external population changes (e.g. immigrant integration).
* Default implementation is a no-op. Override in subclasses that need it.
* @param _pop the population to finalize
*/
virtual void finalize(eoPop<MOEOT>&) {}
};
#endif /*MOEOPOPALGO_H_*/ #endif /*MOEOPOPALGO_H_*/

272
smp/src/MPI_IslandModel.cpp Normal file
View file

@ -0,0 +1,272 @@
/*
<MPI_IslandModel.cpp>
Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012
Alexandre Quemy, Thibault Lasnier - INSA Rouen
Eremey Valetov
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
ParadisEO WebSite : http://paradiseo.gforge.inria.fr
Contact: paradiseo-help@lists.gforge.inria.fr
*/
#include <functional>
#include <algorithm>
#include <mpi.h>
#include <SerializableBase.h>
#include <serial/Parser.h>
#include <utils/eoLogger.h>
template<class EOT>
MPI_IslandModel<EOT>::MPI_IslandModel(AbstractTopology& _topo, int _pollIntervalMs)
: topo(_topo), pollIntervalMs(_pollIntervalMs), running(false)
{
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
MPI_Comm_size(MPI_COMM_WORLD, &num_mpi_ranks);
}
template<class EOT>
void paradiseo::smp::MPI_IslandModel<EOT>::add(AIsland<EOT>& _island)
{
islands.push_back(std::pair<AIsland<EOT>*, bool>(&_island, false));
islands.back().first->setModel(this);
}
template<class EOT>
void MPI_IslandModel<EOT>::operator()() {
running = true;
initModel();
std::thread islandThread;
if (mpi_rank < static_cast<int>(islands.size())) {
auto& it = islands[mpi_rank];
it.first->setRunning();
islandThread = std::thread(&AIsland<EOT>::operator(), it.first);
}
int localIslandRunning = 1;
int globalIslandRunning = 0;
do {
localIslandRunning = (mpi_rank < static_cast<int>(islands.size()) &&
!islands[mpi_rank].first->isStopped()) ? 1 : 0;
send();
MPI_Allreduce(&localIslandRunning, &globalIslandRunning, 1,
MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (globalIslandRunning > 0)
std::this_thread::sleep_for(std::chrono::milliseconds(pollIntervalMs));
} while (globalIslandRunning > 0);
if (islandThread.joinable())
islandThread.join();
for (auto& message : sentMessages)
message.wait();
sentMessages.clear();
// Discard remaining outgoing emigrants — all islands have stopped,
// so migrated individuals would never be processed by recipients.
// Using send() here risks MPI deadlock when multiple ranks each
// have pending emigrants to send but no matching receives posted.
{
std::lock_guard<std::mutex> lock(m);
while (!listEmigrants.empty()) listEmigrants.pop();
}
std::thread lastIntegrationThread;
if (mpi_rank < static_cast<int>(islands.size())) {
lastIntegrationThread = std::thread([&]() {
islands[mpi_rank].first->receive();
});
}
if (lastIntegrationThread.joinable())
lastIntegrationThread.join();
// Wait for any async island.update() tasks launched during the drain phase.
// Without this, islands may be deleted while tasks still reference them.
for (auto& message : sentMessages)
message.wait();
sentMessages.clear();
// Cancel remaining non-blocking sends. After the polling loop and drain,
// any unsent data targets stopped islands — safe to discard.
for (auto& ps : pendingSends) {
MPI_Cancel(&ps.request);
MPI_Wait(&ps.request, MPI_STATUS_IGNORE);
}
pendingSends.clear();
running = false;
}
template<class EOT>
bool paradiseo::smp::MPI_IslandModel<EOT>::update(eoPop<EOT> _data, AIsland<EOT>* _island)
{
std::lock_guard<std::mutex> lock(m);
listEmigrants.push(std::pair<eoPop<EOT>,AIsland<EOT>*>(_data, _island));
return true;
}
template<class EOT>
void paradiseo::smp::MPI_IslandModel<EOT>::setTopology(AbstractTopology& _topo)
{
std::lock_guard<std::mutex> lock(m);
topo = _topo;
if (running) {
topo.construct(islands.size());
for (auto it : islands)
if (!it.second)
topo.isolateNode(table.getLeft()[it.first]);
}
}
template<class EOT>
void paradiseo::smp::MPI_IslandModel<EOT>::send(void) {
// Receive first, then send — prevents accumulation of unprocessed messages.
if (!islands.empty() && mpi_rank < static_cast<int>(islands.size())) {
unsigned myId = mpi_rank;
std::vector<unsigned> neighbors = topo.getIdNeighbors(myId);
for (unsigned idFromNeighbor : neighbors) {
int tag = idFromNeighbor * 1000 + mpi_rank;
int flag = 0;
MPI_Status mpiStatus;
MPI_Iprobe(idFromNeighbor, tag, MPI_COMM_WORLD, &flag, &mpiStatus);
if (flag) {
// Single-message receive: MPI_Iprobe confirmed the complete
// message is available, so MPI_Recv returns immediately.
// This avoids the two-message protocol (size + data) in
// comm.recv(), which can deadlock when the size message
// arrives before the data message is progressed by MPI.
int count = 0;
MPI_Get_count(&mpiStatus, MPI_CHAR, &count);
std::string serialized(count, '\0');
MPI_Recv(&serialized[0], count, MPI_CHAR, idFromNeighbor, tag,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
eoserial::Object* obj = eoserial::Parser::parse(serialized);
SerializableBase<eoPop<EOT>> receivedSerializablePop;
receivedSerializablePop.unpack(obj);
delete obj;
eoPop<EOT> receivedPop = receivedSerializablePop;
eo::log << eo::debug << "MPI_IslandModel: rank " << mpi_rank
<< " received " << receivedPop.size() << " migrant(s) from island "
<< idFromNeighbor << " (tag=" << tag << ")" << std::endl;
sentMessages.push_back(std::async(std::launch::async,
&AIsland<EOT>::update,
table.getRight()[myId],
std::move(receivedPop)));
}
}
}
// Clean up completed async tasks
sentMessages.erase(std::remove_if(sentMessages.begin(), sentMessages.end(),
[](std::shared_future<bool>& i) -> bool
{ return i.wait_for(std::chrono::nanoseconds(0)) == std::future_status::ready; }
),
sentMessages.end());
// Then send outgoing emigrants
eoPop<EOT> migPop;
unsigned idFrom = 0;
bool hasMigrant = false;
{
std::lock_guard<std::mutex> lock(m);
if (!listEmigrants.empty()) {
idFrom = table.getLeft()[listEmigrants.front().second];
migPop = std::move(listEmigrants.front().first);
listEmigrants.pop();
hasMigrant = true;
}
}
if (hasMigrant) {
std::vector<unsigned> neighbors = topo.getIdNeighbors(idFrom);
// Serialize once for all neighbors (same protocol as comm.send for Persistent)
SerializableBase<eoPop<EOT>> serializablePop(migPop);
eoserial::Object* obj = serializablePop.pack();
std::stringstream ss;
obj->print(ss);
delete obj;
std::string serialized = ss.str();
int size = static_cast<int>(serialized.size()) + 1;
for (unsigned idTo : neighbors) {
int tag = idFrom * 1000 + idTo;
eo::log << eo::debug << "MPI_IslandModel: rank " << mpi_rank
<< " sending " << migPop.size() << " migrant(s) from island "
<< idFrom << " to island " << idTo << " (tag=" << tag << ")" << std::endl;
// Single non-blocking send. The receiver uses MPI_Get_count
// from MPI_Iprobe to determine the size, eliminating the
// separate blocking size message that could deadlock.
pendingSends.emplace_back();
PendingSend& ps = pendingSends.back();
ps.buffer = serialized;
MPI_Isend(ps.buffer.data(), size, MPI_CHAR, idTo, tag,
MPI_COMM_WORLD, &ps.request);
}
}
completePendingSends();
}
template<class EOT>
void paradiseo::smp::MPI_IslandModel<EOT>::completePendingSends() {
auto it = pendingSends.begin();
while (it != pendingSends.end()) {
int completed = 0;
MPI_Test(&it->request, &completed, MPI_STATUS_IGNORE);
if (completed)
it = pendingSends.erase(it);
else
++it;
}
}
template<class EOT>
bool paradiseo::smp::MPI_IslandModel<EOT>::isRunning() const
{
return (bool)running;
}
template<class EOT>
void paradiseo::smp::MPI_IslandModel<EOT>::initModel(void)
{
if (num_mpi_ranks > static_cast<int>(islands.size()) + 1) {
eo::log << eo::errors << "MPI_IslandModel: number of MPI ranks ("
<< num_mpi_ranks << ") exceeds number of islands + 1 ("
<< islands.size() + 1 << ")" << std::endl;
MPI_Abort(MPI_COMM_WORLD, 1);
}
for (auto& it : islands)
it.second = true;
topo.construct(islands.size());
table = createTable();
}
template<class EOT>
Bimap<unsigned, AIsland<EOT>*> paradiseo::smp::MPI_IslandModel<EOT>::createTable()
{
Bimap<unsigned, AIsland<EOT>*> table;
unsigned islandId = 0;
for (auto it : islands) {
table.add(islandId, it.first);
islandId++;
}
return table;
}

105
smp/src/MPI_IslandModel.h Normal file
View file

@ -0,0 +1,105 @@
/*
<MPI_IslandModel.h>
Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012
Alexandre Quemy, Thibault Lasnier - INSA Rouen
Eremey Valetov
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
ParadisEO WebSite : http://paradiseo.gforge.inria.fr
Contact: paradiseo-help@lists.gforge.inria.fr
*/
#ifndef SMP_MPI_ISLAND_MODEL_H_
#define SMP_MPI_ISLAND_MODEL_H_
#include <queue>
#include <list>
#include <algorithm>
#include <utility>
#include <future>
#include <thread>
#include <mpi.h>
#include <sstream>
#include <bimap.h>
#include <abstractIsland.h>
#include <topology/topology.h>
namespace paradiseo
{
namespace smp
{
/**
* MPI-distributed island model.
* Each MPI rank runs one island; migration is handled via MPI send/recv
* using SerializableBase for population serialization.
*
* @see smp::Island, smp::MigPolicy
*/
template<class EOT>
class MPI_IslandModel
{
public:
/**
* @param _topo topology defining island connectivity
* @param _pollIntervalMs polling interval in milliseconds (default 1000)
*/
MPI_IslandModel(AbstractTopology& _topo, int _pollIntervalMs = 1000);
void add(AIsland<EOT>& _island);
void operator()();
bool update(eoPop<EOT> _data, AIsland<EOT>* _island);
void setTopology(AbstractTopology& _topo);
bool isRunning() const;
protected:
void send(void);
void initModel(void);
Bimap<unsigned, AIsland<EOT>*> createTable();
// Non-blocking MPI send: buffer must stay alive until send completes
struct PendingSend {
MPI_Request request;
std::string buffer;
};
void completePendingSends();
std::queue<std::pair<eoPop<EOT>,AIsland<EOT>*>> listEmigrants;
Bimap<unsigned, AIsland<EOT>*> table;
std::vector<std::pair<AIsland<EOT>*, bool>> islands;
AbstractTopology& topo;
std::vector<std::shared_future<bool>> sentMessages;
std::list<PendingSend> pendingSends;
std::mutex m;
int mpi_rank, num_mpi_ranks;
int pollIntervalMs;
std::atomic<bool> running;
};
#include <MPI_IslandModel.cpp>
}
}
#endif

View file

@ -0,0 +1,59 @@
/*
<SerializableBase.h>
Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012
Eremey Valetov
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
ParadisEO WebSite : http://paradiseo.gforge.inria.fr
Contact: paradiseo-help@lists.gforge.inria.fr
*/
#ifndef SERIALIZABLE_BASE_H
#define SERIALIZABLE_BASE_H
#include <serial/eoSerial.h>
#include <string>
/**
* Wrapper that makes any type T serializable via ParadisEO's eoserial framework.
* Used by MPI_IslandModel to serialize/deserialize populations for inter-process transfer.
*/
template<class T>
class SerializableBase : public eoserial::Persistent {
public:
SerializableBase();
SerializableBase(T base);
virtual ~SerializableBase();
operator T&();
void setValue(const T& newValue);
void unpack(const eoserial::Object* obj) override;
eoserial::Object* pack() const override;
private:
T _value;
};
#include "SerializableBase.tpp"
#endif // SERIALIZABLE_BASE_H

View file

@ -0,0 +1,46 @@
/*
<SerializableBase.tpp>
Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012
Eremey Valetov
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
ParadisEO WebSite : http://paradiseo.gforge.inria.fr
Contact: paradiseo-help@lists.gforge.inria.fr
*/
template<class T>
SerializableBase<T>::SerializableBase() : _value() {}
template<class T>
SerializableBase<T>::SerializableBase(T base) : _value(std::move(base)) {}
template<class T>
SerializableBase<T>::~SerializableBase() = default;
template<class T>
SerializableBase<T>::operator T&() {
return _value;
}
template<class T>
void SerializableBase<T>::setValue(const T& newValue) {
_value = newValue;
}
template<class T>
void SerializableBase<T>::unpack(const eoserial::Object* obj) {
eoserial::unpack(*obj, "value", _value);
}
template<class T>
eoserial::Object* SerializableBase<T>::pack() const {
eoserial::Object* obj = new eoserial::Object;
obj->add("value", eoserial::make(_value));
return obj;
}

View file

@ -40,10 +40,16 @@ namespace paradiseo
namespace smp namespace smp
{ {
// Forward declaration // Forward declarations
template<class bEOT> template<class bEOT>
class IslandModel; class IslandModel;
template<class bEOT>
class MPI_IslandModel;
template<class bEOT>
class Redis_IslandModel;
/** AbstractIsland: An abstract island. /** AbstractIsland: An abstract island.
The abstract island is used to manipulate island pointers wihout the knowledge of the algorithm. The abstract island is used to manipulate island pointers wihout the knowledge of the algorithm.
@ -64,6 +70,8 @@ public:
* @param _model The model which manipulate the island. * @param _model The model which manipulate the island.
*/ */
virtual void setModel(IslandModel<bEOT>* _model) = 0; virtual void setModel(IslandModel<bEOT>* _model) = 0;
virtual void setModel(MPI_IslandModel<bEOT>*) {}
virtual void setModel(Redis_IslandModel<bEOT>*) {}
/** /**
* Check if there is population to receive or to emigrate. * Check if there is population to receive or to emigrate.

View file

@ -3,6 +3,7 @@
Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012 Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012
Alexandre Quemy, Thibault Lasnier - INSA Rouen Alexandre Quemy, Thibault Lasnier - INSA Rouen
Eremey Valetov
This software is governed by the CeCILL license under French law and This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can ue, abiding by the rules of distribution of free software. You can ue,
@ -10,167 +11,210 @@ modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info". "http://www.cecill.info".
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
ParadisEO WebSite : http://paradiseo.gforge.inria.fr ParadisEO WebSite : http://paradiseo.gforge.inria.fr
Contact: paradiseo-help@lists.gforge.inria.fr Contact: paradiseo-help@lists.gforge.inria.fr
*/ */
template<template <class> class EOAlgo, class EOT, class bEOT> #ifdef _OPENMP
#include <omp.h>
#endif
#include <utils/eoLogger.h>
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
template<class... Args> template<class... Args>
paradiseo::smp::Island<EOAlgo,EOT,bEOT>::Island(std::function<EOT(bEOT&)> _convertFromBase, std::function<bEOT(EOT&)> _convertToBase, eoPop<EOT>& _pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args) : paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::Island(
// The PPExpander looks for the continuator in the parameters pack. std::function<EOT(bEOT&)> _convertFromBase, std::function<bEOT(EOT&)> _convertToBase,
// The private inheritance of ContWrapper wraps the continuator and add islandNotifier. eoPop<EOT>& _pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args) :
ContWrapper<EOT, bEOT>(Loop<Args...>().template findValue<eoContinue<EOT>>(args...), this), ContWrapper<EOT, bEOT>(Loop<Args...>().template findValue<eoContinue<EOT>>(args...), this),
// We inject the wrapped continuator by tag dispatching method during the algorithm construction. algo(EOAlgo<algoEOT>(wrap_pp<eoContinue<EOT>>(this->ck,args)...)),
algo(EOAlgo<EOT>(wrap_pp<eoContinue<EOT>>(this->ck,args)...)),
// With the PPE we look for the eval function in order to evaluate EOT to integrate
eval(Loop<Args...>().template findValue<eoEvalFunc<EOT>>(args...)), eval(Loop<Args...>().template findValue<eoEvalFunc<EOT>>(args...)),
pop(_pop), pop(_pop),
intPolicy(_intPolicy), intPolicy(_intPolicy),
migPolicy(_migPolicy), migPolicy(_migPolicy),
stopped(false), stopped(false),
model(nullptr),
convertFromBase(_convertFromBase), convertFromBase(_convertFromBase),
convertToBase(_convertToBase) convertToBase(_convertToBase)
{ {}
// Check in compile time the inheritance thanks to type_trait.
static_assert(std::is_base_of<eoAlgo<EOT>,EOAlgo<EOT>>::value, "Algorithm must inherit from eoAlgo<EOT>");
}
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
template<class... Args> template<class... Args>
paradiseo::smp::Island<EOAlgo,EOT,bEOT>::Island(eoPop<EOT>& _pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args) : paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::Island(
eoPop<EOT>& _pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args) :
Island( Island(
// Default conversion functions for homogeneous islands
[](bEOT& i) -> EOT { return std::forward<EOT>(i); }, [](bEOT& i) -> EOT { return std::forward<EOT>(i); },
[](EOT& i) -> bEOT { return std::forward<bEOT>(i); }, [](EOT& i) -> bEOT { return std::forward<bEOT>(i); },
_pop, _intPolicy, _migPolicy, args...) _pop, _intPolicy, _migPolicy, args...)
{ } {}
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
paradiseo::smp::Island<EOAlgo,EOT,bEOT>::~Island() template<class... Args>
{ } paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::Island(
std::function<EOT(bEOT&)> _convertFromBase, std::function<bEOT(EOT&)> _convertToBase,
eoPop<EOT>& _pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy,
IslandType islandType, Args&... args) :
ContWrapper<EOT, bEOT>(Loop<Args...>().template findValue<eoContinue<EOT>>(args...), this),
algo(EOAlgo<algoEOT>(wrap_pp<eoContinue<EOT>>(this->ck,args)...)),
eval(Loop<Args...>().template findValue<eoEvalFunc<EOT>>(args...)),
pop(_pop),
intPolicy(_intPolicy),
migPolicy(_migPolicy),
stopped(false),
convertFromBase(_convertFromBase),
convertToBase(_convertToBase),
_islandType(islandType)
{}
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::operator()() template<class... Args>
paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::Island(
eoPop<EOT>& _pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy,
IslandType islandType, Args&... args) :
Island(
[](bEOT& i) -> EOT { return std::forward<EOT>(i); },
[](EOT& i) -> bEOT { return std::forward<bEOT>(i); },
_pop, _intPolicy, _migPolicy, islandType, args...)
{}
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::operator()()
{ {
stopped = false; stopped = false;
algo(pop); algo(pop);
stopped = true; stopped = true;
// Let's wait the end of communications with the island model for (auto& message : sentMessages)
for(auto& message : sentMessages)
message.wait(); message.wait();
// Clear the sentMessages container
sentMessages.clear(); sentMessages.clear();
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::setModel(IslandModel<bEOT>* _model) void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::setModel(IslandModel<bEOT>* _model)
{ {
model = _model; sharedModel_ = _model;
modelKind_ = IslandModelKind::Shared;
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
eoPop<EOT>& paradiseo::smp::Island<EOAlgo,EOT,bEOT>::getPop() const void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::setModel(MPI_IslandModel<bEOT>* _model)
{
mpiModel_ = _model;
modelKind_ = IslandModelKind::MPI;
}
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::setModel(Redis_IslandModel<bEOT>* _model)
{
redisModel_ = _model;
modelKind_ = IslandModelKind::Redis;
}
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
eoPop<EOT>& paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::getPop() const
{ {
return pop; return pop;
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::check() void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::check()
{ {
// Sending for (PolicyElement<EOT>& elem : migPolicy)
for(PolicyElement<EOT>& elem : migPolicy) if (!elem(pop)) {
if(!elem(pop)) eo::log << eo::debug << "Island::check: migration policy triggered, sending migrants (pop size=" << pop.size() << ")" << std::endl;
send(elem.getSelect()); send(elem.getSelect());
}
// Receiving
receive(); receive();
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
bool paradiseo::smp::Island<EOAlgo,EOT,bEOT>::isStopped(void) const bool paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::isStopped(void) const
{ {
return (bool)stopped; return (bool)stopped;
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::setRunning(void) void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::setRunning(void)
{ {
stopped = false; stopped = false;
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::send(eoSelect<EOT>& _select) void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::send(eoSelect<EOT>& _select)
{ {
// Allow island to work alone if (modelKind_ == IslandModelKind::None)
if(model != nullptr) return;
{
eoPop<EOT> migPop;
_select(pop, migPop);
// Convert pop to base pop eoPop<EOT> migPop;
eoPop<bEOT> baseMigPop; _select(pop, migPop);
for(auto& indi : migPop) eo::log << eo::debug << "Island::send: selected " << migPop.size() << " migrant(s) from pop of " << pop.size() << std::endl;
baseMigPop.push_back(std::move(convertToBase(indi)));
// Delete delivered messages eoPop<bEOT> baseMigPop;
sentMessages.erase(std::remove_if(sentMessages.begin(), sentMessages.end(), for (auto& indi : migPop)
[&](std::shared_future<bool>& i) -> bool baseMigPop.push_back(std::move(convertToBase(indi)));
{ return i.wait_for(std::chrono::nanoseconds(0)) == std::future_status::ready; }
),
sentMessages.end());
sentMessages.push_back(std::async(std::launch::async, &IslandModel<bEOT>::update, model, std::move(baseMigPop), this)); sentMessages.erase(std::remove_if(sentMessages.begin(), sentMessages.end(),
[](std::shared_future<bool>& i) -> bool
{ return i.wait_for(std::chrono::nanoseconds(0)) == std::future_status::ready; }
),
sentMessages.end());
switch (modelKind_) {
case IslandModelKind::Shared:
sentMessages.push_back(std::async(std::launch::async,
&IslandModel<bEOT>::update, sharedModel_,
std::move(baseMigPop), this));
break;
case IslandModelKind::MPI:
sentMessages.push_back(std::async(std::launch::async,
&MPI_IslandModel<bEOT>::update, mpiModel_,
std::move(baseMigPop), this));
break;
case IslandModelKind::Redis:
sentMessages.push_back(std::async(std::launch::async,
&Redis_IslandModel<bEOT>::update, redisModel_,
std::move(baseMigPop), this));
break;
case IslandModelKind::None:
break;
} }
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::receive(void) void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::receive(void)
{ {
std::lock_guard<std::mutex> lock(this->m); std::lock_guard<std::mutex> lock(this->m);
while (!listImigrants.empty())
{
eoPop<bEOT> base_offspring = std::move(listImigrants.front());
// Convert objects from base to our objects type while (!listImigrants.empty()) {
eoPop<bEOT> base_offspring = std::move(listImigrants.front());
eo::log << eo::debug << "Island::receive: integrating " << base_offspring.size()
<< " immigrant(s) into pop of " << pop.size() << std::endl;
eoPop<EOT> offspring; eoPop<EOT> offspring;
for(auto& indi : base_offspring) for (auto& indi : base_offspring)
offspring.push_back(std::move(convertFromBase(indi))); offspring.push_back(std::move(convertFromBase(indi)));
// Evaluate objects to integrate // Re-evaluate immigrants for heterogeneous islands
// We first invalidate the individuals in order to explicitly force the evaluation if (_islandType == HETEROGENEOUS_ISLAND) {
for(auto& indi : offspring) #ifdef _OPENMP
{ #pragma omp parallel for
indi.invalidate(); #endif
eval(indi); for (size_t i = 0; i < offspring.size(); ++i) {
offspring[i].invalidate();
eval(offspring[i]);
}
} }
intPolicy(pop, offspring); intPolicy(pop, offspring);
listImigrants.pop();
if (algo.hasFinalize())
algo.finalize(pop);
listImigrants.pop();
} }
} }
template<template <class> class EOAlgo, class EOT, class bEOT> template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
bool paradiseo::smp::Island<EOAlgo,EOT,bEOT>::update(eoPop<bEOT> _data) bool paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::update(eoPop<bEOT> _data)
{ {
//std::cout << "On update dans l'île" << std::endl;
std::lock_guard<std::mutex> lock(this->m); std::lock_guard<std::mutex> lock(this->m);
listImigrants.push(_data); listImigrants.push(_data);
return true; return true;
} }

View file

@ -3,6 +3,7 @@
Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012 Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012
Alexandre Quemy, Thibault Lasnier - INSA Rouen Alexandre Quemy, Thibault Lasnier - INSA Rouen
Eremey Valetov
This software is governed by the CeCILL license under French law and This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can ue, abiding by the rules of distribution of free software. You can ue,
@ -51,24 +52,35 @@ Contact: paradiseo-help@lists.gforge.inria.fr
#include <contWrapper.h> #include <contWrapper.h>
#include <contDispatching.h> #include <contDispatching.h>
#include <MPI_IslandModel.h>
namespace paradiseo namespace paradiseo
{ {
namespace smp namespace smp
{ {
enum IslandType {
HOMOGENEOUS_ISLAND,
HETEROGENEOUS_ISLAND,
DEFAULT = HETEROGENEOUS_ISLAND
};
/** Island: Concrete island that wraps an algorithm /** Island: Concrete island that wraps an algorithm
The island wraps an algorithm and provide mecanisms for emigration and integration of populations. The island wraps an algorithm and provide mecanisms for emigration and integration of populations.
An island also have a base type which represents the type of individuals of the Island Model. An island also have a base type which represents the type of individuals of the Island Model.
The optional algoEOT template parameter allows the algorithm to operate on a different
type than the island's EOT (useful when the algorithm's MOEOT differs from the base type).
@see smp::AbstractIsland, smp::MigPolicy @see smp::AbstractIsland, smp::MigPolicy
*/ */
template<template <class> class EOAlgo, class EOT, class bEOT = EOT> template<template <class> class EOAlgo, class EOT, class bEOT = EOT, class algoEOT = EOT>
class Island : private ContWrapper<EOT, bEOT>, public AIsland<bEOT> class Island : private ContWrapper<EOT, bEOT>, public AIsland<bEOT>
{ {
public: public:
/** /**
* Constructor * Constructor with type converters
* @param _convertFromBase Function to convert EOT from base EOT * @param _convertFromBase Function to convert EOT from base EOT
* @param _convertToBase Function to convert base EOT to EOT * @param _convertToBase Function to convert base EOT to EOT
* @param _pop Population of the island * @param _pop Population of the island
@ -77,73 +89,47 @@ public:
* @param args Parameters to construct the algorithm. * @param args Parameters to construct the algorithm.
*/ */
template<class... Args> template<class... Args>
Island(std::function<EOT(bEOT&)> _convertFromBase, std::function<bEOT(EOT&)> _convertToBase, eoPop<EOT>& pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args); Island(std::function<EOT(bEOT&)> _convertFromBase, std::function<bEOT(EOT&)> _convertToBase,
eoPop<EOT>& pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args);
/** /**
* Constructor * Constructor for homogeneous islands (bEOT == EOT)
* @param _pop Population of the island
* @param _intPolicy Integration policy
* @param _migPolicy Migration policy
* @param args Parameters to construct the algorithm.
*/ */
template<class... Args> template<class... Args>
Island(eoPop<EOT>& pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args); Island(eoPop<EOT>& pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy, Args&... args);
/** /**
* Start the island. * Constructor with type converters and island type
*/ */
template<class... Args>
Island(std::function<EOT(bEOT&)> _convertFromBase, std::function<bEOT(EOT&)> _convertToBase,
eoPop<EOT>& pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy,
IslandType islandType, Args&... args);
/**
* Constructor with island type
*/
template<class... Args>
Island(eoPop<EOT>& pop, IntPolicy<EOT>& _intPolicy, MigPolicy<EOT>& _migPolicy,
IslandType islandType, Args&... args);
void operator()(void); void operator()(void);
/**
* Set model
* @param _model Pointer to the Island Model corresponding
*/
virtual void setModel(IslandModel<bEOT>* _model); virtual void setModel(IslandModel<bEOT>* _model);
virtual void setModel(MPI_IslandModel<bEOT>* _model);
virtual void setModel(Redis_IslandModel<bEOT>* _model);
/**
* Return a reference to the island population.
* @return Reference to the island population
*/
eoPop<EOT>& getPop() const; eoPop<EOT>& getPop() const;
/**
* Check if there is population to receive or to migrate
*/
virtual void check(void); virtual void check(void);
/**
* Update the list of imigrants.
* @param _data Elements to integrate in the main population.
*/
bool update(eoPop<bEOT> _data); bool update(eoPop<bEOT> _data);
/**
* Check if the algorithm is stopped.
* @return true if stopped
*/
virtual bool isStopped(void) const; virtual bool isStopped(void) const;
/**
* Set the stopped indicator on false
*/
virtual void setRunning(void); virtual void setRunning(void);
/**
* Check if there is population to receive
*/
virtual void receive(void); virtual void receive(void);
//AIsland<bEOT> clone() const;
virtual ~Island();
protected: protected:
/**
* Send population to mediator
* @param _select Method to select EOT to send
*/
virtual void send(eoSelect<EOT>& _select); virtual void send(eoSelect<EOT>& _select);
EOAlgo<EOT> algo; EOAlgo<algoEOT> algo;
eoEvalFunc<EOT>& eval; eoEvalFunc<EOT>& eval;
eoPop<EOT>& pop; eoPop<EOT>& pop;
std::queue<eoPop<bEOT>> listImigrants; std::queue<eoPop<bEOT>> listImigrants;
@ -151,9 +137,16 @@ protected:
MigPolicy<EOT>& migPolicy; MigPolicy<EOT>& migPolicy;
std::atomic<bool> stopped; std::atomic<bool> stopped;
std::vector<std::shared_future<bool>> sentMessages; std::vector<std::shared_future<bool>> sentMessages;
IslandModel<bEOT>* model;
enum class IslandModelKind { None, Shared, MPI, Redis };
IslandModelKind modelKind_ = IslandModelKind::None;
IslandModel<bEOT>* sharedModel_ = nullptr;
MPI_IslandModel<bEOT>* mpiModel_ = nullptr;
Redis_IslandModel<bEOT>* redisModel_ = nullptr;
std::function<EOT(bEOT&)> convertFromBase; std::function<EOT(bEOT&)> convertFromBase;
std::function<bEOT(EOT&)> convertToBase; std::function<bEOT(EOT&)> convertToBase;
IslandType _islandType = DEFAULT;
}; };
#include <island.cpp> #include <island.cpp>

View file

@ -3,6 +3,7 @@
Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012 Copyright (C) DOLPHIN Project-Team, INRIA Lille - Nord Europe, 2006-2012
Alexandre Quemy, Thibault Lasnier - INSA Rouen Alexandre Quemy, Thibault Lasnier - INSA Rouen
Eremey Valetov
This software is governed by the CeCILL license under French law and This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can ue, abiding by the rules of distribution of free software. You can ue,
@ -36,6 +37,7 @@ Contact: paradiseo-help@lists.gforge.inria.fr
#include <thread> #include <thread>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <cassert>
#include <bimap.h> #include <bimap.h>
#include <abstractIsland.h> #include <abstractIsland.h>
@ -55,36 +57,132 @@ of specified islands, built with same parameters.
@see smp::IslandModel @see smp::IslandModel
*/ */
// Original overload: uses IslandModel (shared-memory)
template<template <class> class EOAlgo, class EOT, class... IslandInit> template<template <class> class EOAlgo, class EOT, class... IslandInit>
std::vector<eoPop<EOT>> IslandModelWrapper(unsigned _islandNumber, AbstractTopology& _topo, unsigned _popSize, eoInit<EOT> &_chromInit, IslandInit&&... args) std::vector<eoPop<EOT>> IslandModelWrapper(unsigned _islandNumber, AbstractTopology& _topo, unsigned _popSize, eoInit<EOT> &_chromInit, IslandInit&&... args)
{ {
// Model creation
IslandModel<EOT> model(_topo); IslandModel<EOT> model(_topo);
// Island and pop containers
std::vector<Island<EOAlgo,EOT>*> islands(_islandNumber); std::vector<Island<EOAlgo,EOT>*> islands(_islandNumber);
std::vector<eoPop<EOT>> pops(_islandNumber); std::vector<eoPop<EOT>> pops(_islandNumber);
// Generate islands and put them in the model for (unsigned i = 0; i < _islandNumber; i++) {
for(unsigned i = 0; i < _islandNumber; i++)
{
pops[i] = eoPop<EOT>(_popSize, _chromInit); pops[i] = eoPop<EOT>(_popSize, _chromInit);
islands[i] = new Island<EOAlgo, EOT>(pops[i], args...); islands[i] = new Island<EOAlgo, EOT>(pops[i], args...);
model.add(*islands[i]); model.add(*islands[i]);
} }
// Start the model
model(); model();
// Delete islands for (auto& island : islands)
for(auto& island : islands) delete island;
return pops;
}
// Overload with configurable IslandModelType template parameter
template<template <class> class EOAlgo, class EOT, template <class> class IslandModelType, class... IslandInit>
std::vector<eoPop<EOT>> IslandModelWrapper(unsigned _islands, AbstractTopology& _topo, unsigned _popSize, eoInit<EOT> &_chromInit, IslandInit&&... args)
{
IslandModelType<EOT> model(_topo);
std::vector<Island<EOAlgo,EOT>*> islands(_islands);
std::vector<eoPop<EOT>> pops(_islands);
for (unsigned i = 0; i < _islands; i++) {
pops[i] = eoPop<EOT>(_popSize, _chromInit);
islands[i] = new Island<EOAlgo, EOT>(pops[i], std::forward<IslandInit>(args)...);
model.add(*islands[i]);
}
model();
for (auto& island : islands)
delete island;
return pops;
}
// Overload with initial_values for seeding populations
template<template <class> class EOAlgo, class EOT, template <class> class IslandModelType, class... IslandInit>
std::vector<eoPop<EOT>> IslandModelWrapper(unsigned _islands, AbstractTopology& _topo, unsigned _popSize, const std::vector<std::vector<double>> &initial_values, eoInit<EOT> &_chromInit, IslandInit&&... args)
{
IslandModelType<EOT> model(_topo);
std::vector<Island<EOAlgo,EOT>*> islands(_islands);
std::vector<eoPop<EOT>> pops(_islands);
for (unsigned i = 0; i < _islands; i++) {
pops[i] = eoPop<EOT>(_popSize, _chromInit);
for (size_t j = 0; j < initial_values.size() && j < pops[i].size(); j++) {
assert(initial_values[j].size() == pops[i][j].size());
for (size_t k = 0; k < initial_values[j].size(); k++)
pops[i][j][k] = initial_values[j][k];
}
islands[i] = new Island<EOAlgo, EOT>(pops[i], std::forward<IslandInit>(args)...);
model.add(*islands[i]);
}
model();
for (auto& island : islands)
delete island;
return pops;
}
// Overload with algoEOT template parameter (for algorithms operating on a different type)
template<template <class> class EOAlgo, class EOT, class algoEOT, template <class> class IslandModelType, class... IslandInit>
std::vector<eoPop<EOT>> IslandModelWrapper(unsigned _islands, AbstractTopology& _topo, unsigned _popSize, eoInit<EOT> &_chromInit, IslandInit&&... args)
{
IslandModelType<EOT> model(_topo);
std::vector<Island<EOAlgo,EOT,EOT,algoEOT>*> islands(_islands);
std::vector<eoPop<EOT>> pops(_islands);
for (unsigned i = 0; i < _islands; i++) {
pops[i] = eoPop<EOT>(_popSize, _chromInit);
islands[i] = new Island<EOAlgo, EOT, EOT, algoEOT>(pops[i], std::forward<IslandInit>(args)...);
model.add(*islands[i]);
}
model();
for (auto& island : islands)
delete island;
return pops;
}
// Overload with algoEOT and initial_values
template<template <class> class EOAlgo, class EOT, class algoEOT, template <class> class IslandModelType, class... IslandInit>
std::vector<eoPop<EOT>> IslandModelWrapper(unsigned _islands, AbstractTopology& _topo, unsigned _popSize, const std::vector<std::vector<double>> &initial_values, eoInit<EOT> &_chromInit, IslandInit&&... args)
{
IslandModelType<EOT> model(_topo);
std::vector<Island<EOAlgo,EOT,EOT,algoEOT>*> islands(_islands);
std::vector<eoPop<EOT>> pops(_islands);
for (unsigned i = 0; i < _islands; i++) {
pops[i] = eoPop<EOT>(_popSize, _chromInit);
for (size_t j = 0; j < initial_values.size() && j < pops[i].size(); j++) {
assert(initial_values[j].size() == pops[i][j].size());
for (size_t k = 0; k < initial_values[j].size(); k++)
pops[i][j][k] = initial_values[j][k];
}
islands[i] = new Island<EOAlgo, EOT, EOT, algoEOT>(pops[i], std::forward<IslandInit>(args)...);
model.add(*islands[i]);
}
model();
for (auto& island : islands)
delete island; delete island;
return pops; return pops;
} }
} }
} }
#endif #endif

View file

@ -32,7 +32,9 @@ Contact: paradiseo-help@lists.gforge.inria.fr
#include <MWModel.h> #include <MWModel.h>
#include <scheduler.h> #include <scheduler.h>
#include <SerializableBase.h>
#include <islandModel.h> #include <islandModel.h>
#include <MPI_IslandModel.h>
#include <islandModelWrapper.h> #include <islandModelWrapper.h>
#include <island.h> #include <island.h>
#include <abstractIsland.h> #include <abstractIsland.h>