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.
*/
class moeoAlgo
{};
{
public:
virtual ~moeoAlgo() = default;
/** Whether this algorithm supports finalize() for post-integration updates. */
virtual bool hasFinalize() const { return false; }
};
#endif /*MOEOALGO_H_*/

View file

@ -148,6 +148,17 @@ public:
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:

View file

@ -47,6 +47,14 @@
*/
template < class 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_*/

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
{
// Forward declaration
// Forward declarations
template<class bEOT>
class IslandModel;
template<class bEOT>
class MPI_IslandModel;
template<class bEOT>
class Redis_IslandModel;
/** AbstractIsland: An abstract island.
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.
*/
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.

View file

@ -3,6 +3,7 @@
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 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
"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
*/
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>
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) :
// The PPExpander looks for the continuator in the parameters pack.
// The private inheritance of ContWrapper wraps the continuator and add islandNotifier.
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, Args&... args) :
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<EOT>(wrap_pp<eoContinue<EOT>>(this->ck,args)...)),
// With the PPE we look for the eval function in order to evaluate EOT to integrate
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),
model(nullptr),
convertFromBase(_convertFromBase),
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>
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(
// Default conversion functions for homogeneous islands
[](bEOT& i) -> EOT { return std::forward<EOT>(i); },
[](EOT& i) -> bEOT { return std::forward<bEOT>(i); },
_pop, _intPolicy, _migPolicy, args...)
{ }
{}
template<template <class> class EOAlgo, class EOT, class bEOT>
paradiseo::smp::Island<EOAlgo,EOT,bEOT>::~Island()
{ }
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
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>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::operator()()
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
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;
algo(pop);
stopped = true;
// Let's wait the end of communications with the island model
for(auto& message : sentMessages)
for (auto& message : sentMessages)
message.wait();
// Clear the sentMessages container
sentMessages.clear();
}
template<template <class> class EOAlgo, class EOT, class bEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::setModel(IslandModel<bEOT>* _model)
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
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>
eoPop<EOT>& paradiseo::smp::Island<EOAlgo,EOT,bEOT>::getPop() const
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
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;
}
template<template <class> class EOAlgo, class EOT, class bEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::check()
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::check()
{
// Sending
for(PolicyElement<EOT>& elem : migPolicy)
if(!elem(pop))
for (PolicyElement<EOT>& elem : migPolicy)
if (!elem(pop)) {
eo::log << eo::debug << "Island::check: migration policy triggered, sending migrants (pop size=" << pop.size() << ")" << std::endl;
send(elem.getSelect());
// Receiving
}
receive();
}
template<template <class> class EOAlgo, class EOT, class bEOT>
bool paradiseo::smp::Island<EOAlgo,EOT,bEOT>::isStopped(void) const
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
bool paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::isStopped(void) const
{
return (bool)stopped;
}
template<template <class> class EOAlgo, class EOT, class bEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::setRunning(void)
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::setRunning(void)
{
stopped = false;
}
template<template <class> class EOAlgo, class EOT, class bEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::send(eoSelect<EOT>& _select)
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::send(eoSelect<EOT>& _select)
{
// Allow island to work alone
if(model != nullptr)
{
eoPop<EOT> migPop;
_select(pop, migPop);
if (modelKind_ == IslandModelKind::None)
return;
// Convert pop to base pop
eoPop<bEOT> baseMigPop;
for(auto& indi : migPop)
baseMigPop.push_back(std::move(convertToBase(indi)));
eoPop<EOT> migPop;
_select(pop, migPop);
eo::log << eo::debug << "Island::send: selected " << migPop.size() << " migrant(s) from pop of " << pop.size() << std::endl;
// Delete delivered messages
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());
eoPop<bEOT> baseMigPop;
for (auto& indi : migPop)
baseMigPop.push_back(std::move(convertToBase(indi)));
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>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT>::receive(void)
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
void paradiseo::smp::Island<EOAlgo,EOT,bEOT,algoEOT>::receive(void)
{
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;
for(auto& indi : base_offspring)
for (auto& indi : base_offspring)
offspring.push_back(std::move(convertFromBase(indi)));
// Evaluate objects to integrate
// We first invalidate the individuals in order to explicitly force the evaluation
for(auto& indi : offspring)
{
indi.invalidate();
eval(indi);
// Re-evaluate immigrants for heterogeneous islands
if (_islandType == HETEROGENEOUS_ISLAND) {
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (size_t i = 0; i < offspring.size(); ++i) {
offspring[i].invalidate();
eval(offspring[i]);
}
}
intPolicy(pop, offspring);
listImigrants.pop();
if (algo.hasFinalize())
algo.finalize(pop);
listImigrants.pop();
}
}
template<template <class> class EOAlgo, class EOT, class bEOT>
bool paradiseo::smp::Island<EOAlgo,EOT,bEOT>::update(eoPop<bEOT> _data)
template<template <class> class EOAlgo, class EOT, class bEOT, class algoEOT>
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);
listImigrants.push(_data);
return true;
}

View file

@ -3,6 +3,7 @@
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 ue,
@ -51,24 +52,35 @@ Contact: paradiseo-help@lists.gforge.inria.fr
#include <contWrapper.h>
#include <contDispatching.h>
#include <MPI_IslandModel.h>
namespace paradiseo
{
namespace smp
{
enum IslandType {
HOMOGENEOUS_ISLAND,
HETEROGENEOUS_ISLAND,
DEFAULT = HETEROGENEOUS_ISLAND
};
/** Island: Concrete island that wraps an algorithm
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.
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
*/
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>
{
public:
/**
* Constructor
* Constructor with type converters
* @param _convertFromBase Function to convert EOT from base EOT
* @param _convertToBase Function to convert base EOT to EOT
* @param _pop Population of the island
@ -77,73 +89,47 @@ public:
* @param args Parameters to construct the algorithm.
*/
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
* @param _pop Population of the island
* @param _intPolicy Integration policy
* @param _migPolicy Migration policy
* @param args Parameters to construct the algorithm.
* Constructor for homogeneous islands (bEOT == EOT)
*/
template<class... 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);
/**
* Set model
* @param _model Pointer to the Island Model corresponding
*/
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;
/**
* Check if there is population to receive or to migrate
*/
virtual void check(void);
/**
* Update the list of imigrants.
* @param _data Elements to integrate in the main population.
*/
bool update(eoPop<bEOT> _data);
/**
* Check if the algorithm is stopped.
* @return true if stopped
*/
virtual bool isStopped(void) const;
/**
* Set the stopped indicator on false
*/
virtual void setRunning(void);
/**
* Check if there is population to receive
*/
virtual void receive(void);
//AIsland<bEOT> clone() const;
virtual ~Island();
protected:
/**
* Send population to mediator
* @param _select Method to select EOT to send
*/
virtual void send(eoSelect<EOT>& _select);
EOAlgo<EOT> algo;
EOAlgo<algoEOT> algo;
eoEvalFunc<EOT>& eval;
eoPop<EOT>& pop;
std::queue<eoPop<bEOT>> listImigrants;
@ -151,9 +137,16 @@ protected:
MigPolicy<EOT>& migPolicy;
std::atomic<bool> stopped;
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<bEOT(EOT&)> convertToBase;
IslandType _islandType = DEFAULT;
};
#include <island.cpp>

View file

@ -3,6 +3,7 @@
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 ue,
@ -36,6 +37,7 @@ Contact: paradiseo-help@lists.gforge.inria.fr
#include <thread>
#include <tuple>
#include <vector>
#include <cassert>
#include <bimap.h>
#include <abstractIsland.h>
@ -55,36 +57,132 @@ of specified islands, built with same parameters.
@see smp::IslandModel
*/
// Original overload: uses IslandModel (shared-memory)
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)
{
// Model creation
IslandModel<EOT> model(_topo);
// Island and pop containers
std::vector<Island<EOAlgo,EOT>*> islands(_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);
islands[i] = new Island<EOAlgo, EOT>(pops[i], args...);
model.add(*islands[i]);
}
// Start the 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;
return pops;
}
}
}
#endif

View file

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