manual merge in favor of the CMakeLists of the fusion branch

This commit is contained in:
Johann Dreo 2012-12-18 11:39:06 +01:00
commit 291bb7ce14
967 changed files with 137738 additions and 846 deletions

5
eo/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*.swp
debug/
release/
*CMakeFiles*
*Makefile

View file

@ -1,12 +0,0 @@
Pedro Angel Castillo Valdivieso
Juan Julian Merelo Guervos
Victor Manuel Rivas Santos
Gustavo Romero Lopez
Maarten Keijzer
Marc Schoenauer
Jeroen Eggermont
Jochen K<>pper
Thomas Legrand
Clive Canape
Johann Dréo <johann.dreo@thalesgroup.com>
Caner Candan <caner.candan@thalesgroup.com>

View file

@ -1,116 +1,53 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
######################################################################################
### 0) If you want to set your variables in eo-conf.cmake and avoid the cmd line
######################################################################################
#INCLUDE(eo-conf.cmake OPTIONAL)
######################################################################################
######################################################################################
### 1) Main project config
######################################################################################
# set the project namef and other variables
PROJECT(EO)
# CMake > 2.8 is needed, because of the FindOpenMP feature
#cmake_minimum_required(VERSION 2.8)
#SET(PROJECT_VERSION_MAJOR 1)
#SET(PROJECT_VERSION_MINOR 1)
#SET(PROJECT_VERSION_PATCH 1)
SET(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}" CACHE STRING "Package version" FORCE)
SET(VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${PROJECT_VERSION_MISC}" CACHE STRING "Global version" FORCE)
SET(GLOBAL_VERSION "${VERSION}")
SET(PACKAGE_BUGREPORT "eodev-help@sourceforge.net" CACHE STRING "Package bug report" FORCE)
SET(PACKAGE_NAME "Evolving Objects" CACHE STRING "Package name" FORCE)
SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}"CACHE STRING "Package string full name" FORCE)
SET(PACKAGE_TARNAME "eo" CACHE STRING "Package tar name" FORCE)
# regular expression checking
INCLUDE_REGULAR_EXPRESSION("^.*$" "^$")
# set a language for the entire project.
ENABLE_LANGUAGE(CXX)
ENABLE_LANGUAGE(C)
######################################################################################
#####################################################################################
### 2) Include required modules / configuration files
### Include required modules / configuration files
#####################################################################################
FIND_PACKAGE(OpenMP)
IF(OPENMP_FOUND)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
ENDIF()
# For eo::mpi
enable_language(C)
INCLUDE(CMakeBackwardCompatibilityCXX)
# For openmp parallel
if(ENABLE_OPENMP)
find_package(OpenMP)
if(OPENMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
else()
message( "ERROR: You asked for OpenMP but it has not been found." )
set(IS_FATAL 1)
endif(OPENMP_FOUND)
endif(ENABLE_OPENMP)
INCLUDE(FindDoxygen)
if(ENABLE_GNUPLOT)
include(FindGnuplot)
endif(ENABLE_GNUPLOT)
INCLUDE(FindGnuplot)
# set a special flag if the environment is windows (should do the same in a config.g file)
if (WIN32)
add_definitions(-D_WINDOWS=1)
endif (WIN32)
INCLUDE(CheckLibraryExists)
IF(UNIX)
INCLUDE(ConfigureChecks.cmake)
ENDIF(UNIX)
INCLUDE(Dart OPTIONNAL)
#####################################################################################
### Include required modules / configuration files
#####################################################################################
# now create config headers
CONFIGURE_FILE(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
# now create config install_symlink script file
CONFIGURE_FILE(install_symlink.py.cmake ${CMAKE_CURRENT_BINARY_DIR}/install_symlink.py)
# now create PKGBUILD file for archlinux package manager
CONFIGURE_FILE(PKGBUILD.cmake ${CMAKE_CURRENT_BINARY_DIR}/PKGBUILD)
# Set a special flag if the environment is windows (should do the same in a config.g file)
IF (WIN32)
ADD_DEFINITIONS(-D_WINDOWS=1)
ENDIF (WIN32)
######################################################################################
######################################################################################
configure_file(install_symlink.py.cmake ${CMAKE_CURRENT_BINARY_DIR}/install_symlink.py)
######################################################################################
### compilation of examples?
######################################################################################
#SET(ENABLE_CMAKE_EXAMPLE TRUE CACHE BOOL "Enable copy of benchs and parameters file?")
### Include subdirectories
######################################################################################
######################################################################################
### 4) Test config
######################################################################################
#IF (ENABLE_CMAKE_TESTING)
# ENABLE_TESTING()
#ENDIF (ENABLE_CMAKE_TESTING)
######################################################################################
######################################################################################
### 5) Where must cmake go now ?
######################################################################################
#ADD_SUBDIRECTORY(app)
ADD_SUBDIRECTORY(doc)
ADD_SUBDIRECTORY(src)
add_subdirectory(doc)
add_subdirectory(src)
if(ENABLE_CMAKE_TESTING)
add_subdirectory(test)
@ -118,31 +55,9 @@ endif(ENABLE_CMAKE_TESTING)
if(ENABLE_CMAKE_EXAMPLE)
if(${CMAKE_VERBOSE_MAKEFILE})
message("EO Examples :")
message("EO examples:")
endif(${CMAKE_VERBOSE_MAKEFILE})
add_subdirectory(tutorial)
#add_subdirectory(app) # FIXME must be updated
endif(ENABLE_CMAKE_EXAMPLE)
######################################################################################
######################################################################################
### 6) Install pkg-config config file for EO
######################################################################################
SET(PCPREFIX "/usr")
SET(PCFLAGS "-leoutils -leo -les -lga -lcma -lgcov")
SET(PCINCLUDEDIR "eo")
CONFIGURE_FILE(pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/eo.pc)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/eo.pc DESTINATION ${LIB}/pkgconfig COMPONENT headers)
######################################################################################
######################################################################################
### 7) Include packaging
######################################################################################
#INCLUDE(Packaging.cmake)
######################################################################################

View file

@ -1,45 +0,0 @@
In order to create a new release from the current repository, perform the
following steps:
- If necessary, create a branch named "eo_x.y.z"
- Set version number in eo-conf.cmake
- Check/update NEWS file, set release date and version in NEWS.
- use the "archive_current.sh" script to create the source archive
- Build the packages
- Put source archive and packages files at SourceForge
- Post news on SourceForge project-page
- Send announcement to mailing lists
- Bump version number to next "x.y.z-edge" in eo-conf.cmake
When reaching stable versions:
- prepare a message with the following template:
-----8<-----
A new version of the "Evolving Objects" framework is available.
EO is a template-based, C++ evolutionary computation library which
helps you to write your own stochastic optimization algorithms
insanely fast.
Learn more about EO on the official website:
http://eodev.sourceforge.net/
You will find the release x.y.z at the following address:
https://sourceforge.net/projects/eodev/files/eo/
Here is a summary of the change log:
- XXXXX
- and more…
Do not hesitate to submit the bugs you will face:
https://sourceforge.net/apps/trac/eodev/wiki/WikiStart
Happy evolutionary hacking.
-----8<-----
- Post the message to:
- EO news https://sourceforge.net/news/?group_id=9775
- EO mailing list: eodev-main@lists.sourceforge.net
- ParadisEO mailing list: paradiseo-users@lists.gforge.inria.fr
- EC-digest maling list: ec-digest-l@listserv.gmu.edu
- JET mailing list: jet@inria.fr

37
eo/NEWS
View file

@ -1,4 +1,29 @@
* current version
* current release:
* release 1.3.1 (2012-07-27)
- the eo::mpi modules is no longer dependent from boost::mpi
- parallel multi-start example
- bugfix: an error is now thrown when accessing best_element of an empty population
* release 1.3.0 (2012-07-24)
- features:
- delete the deprecated code parts (was marked as deprecated in the release 1.1)
- eoSignal: a class to handle signal with eoCheckpoint instances
- eoDetSingleBitFlip: bit flip mutation that changes exactly k bits while checking for duplicate
- eoFunctorStat: a wrapper to turn any stand-alone function and into an eoStat
- generilazed the output of an eoState: now you can change the format, comes with defaults formatting (latex and json)
- eoWrongParamTypeException: a new exception to handle cases where a wrong template is given to eoParser::valueOf
- added a getParam method to the eoParser, that raise an exception if the parameter has not been declared
- eoParserLogger features are now included in the default eoParser
- build system:
- improvements of the build architecture
- create PKGBUILD file for archlinux package manager
- a FindEO module for CMake
- bugfixes:
- fixed regression with gcc 4.7
- fixed compilation issues in Microsoft Visual C++, related to time measurement
- added several asserts accross the framework (note: asserts are included only in debug mode)
- lot of small bugfixes :-)
* release 1.2 (16. May. 2011)
- fixed the incremental allocation issue in variation operators which were
@ -20,11 +45,11 @@
- GCC 4.3 compatibility
- new versatile log system with several nested verbose levels
- classes using intern verbose parameters marked as deprecated, please update your code accordingly if you use one of the following files:
eo/src/eoCombinedInit.h
eo/src/eoGenContinue.h
eo/src/eoProportionalCombinedOp.h
eo/src/utils/eoData.h
eo/src/utils/eoStdoutMonitor.h
eo/src/eoCombinedInit.h
eo/src/eoGenContinue.h
eo/src/eoProportionalCombinedOp.h
eo/src/utils/eoData.h
eo/src/utils/eoStdoutMonitor.h
- an evaluator that throw an exception if a maximum eval numbers has been reached, independently of the number of generations
- new monitor that can write on any ostream
- new continuator that can catch POSIX system user signals

View file

@ -2,30 +2,30 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Specify where CMake can find the libraries (mandatory: before 3) )
### 2) specify where cmake can find the libraries (mandatory: before 3) )
######################################################################################
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
link_directories(${EO_BIN_DIR}/lib)
######################################################################################
### 3) Define your target(s): just an executable here
### 3) define your target(s): just an executable here
######################################################################################
SET (GPROP_SOURCES gprop.cpp)
set (GPROP_SOURCES gprop.cpp)
# especially for Visual Studio
IF(NOT WIN32 OR CYGWIN)
ADD_EXECUTABLE(gprop ${GPROP_SOURCES})
ADD_DEPENDENCIES(gprop eo eoutils)
if(NOT WIN32 OR CYGWIN)
add_executable(gprop ${GPROP_SOURCES})
add_dependencies(gprop eo eoutils)
TARGET_LINK_LIBRARIES(gprop eo eoutils)
target_link_libraries(gprop eo eoutils)
SET(GPROP_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(gprop PROPERTIES VERSION "${GPROP_VERSION}")
ENDIF(NOT WIN32 OR CYGWIN)
set(GPROP_VERSION ${GLOBAL_VERSION})
set_target_properties(gprop PROPERTIES VERSION "${GPROP_VERSION}")
endif(NOT WIN32 OR CYGWIN)
######################################################################################

View file

@ -2,37 +2,37 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Specify where CMake can find the libraries (mandatory: before 3) )
### 2) specify where cmake can find the libraries (mandatory: before 3) )
######################################################################################
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
link_directories(${EO_BIN_DIR}/lib)
######################################################################################
### 3) Define your target(s): just an executable here
### 3) define your target(s): just an executable here
######################################################################################
SET (GPSYMREG_SOURCES main.cpp)
set (GPSYMREG_SOURCES main.cpp)
# no matter what is the OS, hopefully
ADD_EXECUTABLE(gpsymreg ${GPSYMREG_SOURCES})
add_executable(gpsymreg ${GPSYMREG_SOURCES})
ADD_DEPENDENCIES(gpsymreg eo eoutils)
add_dependencies(gpsymreg eo eoutils)
######################################################################################
### 4) Optionnal: define your target(s)'s version: no effect for windows
### 4) optionnal: define your target(s)'s version: no effect for windows
######################################################################################
SET(GPSYMREG_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(gpsymreg PROPERTIES VERSION "${GPSYMREG_VERSION}")
set(GPSYMREG_VERSION ${GLOBAL_VERSION})
set_target_properties(gpsymreg PROPERTIES VERSION "${GPSYMREG_VERSION}")
######################################################################################
### 5) Link the librairies for your target(s)
### 5) link the librairies for your target(s)
######################################################################################
TARGET_LINK_LIBRARIES(gpsymreg eo eoutils)
target_link_libraries(gpsymreg eo eoutils)
######################################################################################

View file

@ -2,14 +2,14 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${EO_SRC_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Specify where CMake can find the libraries (mandatory: before 3) )
######################################################################################
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
LINK_DIRECTORIES(${EO_BIN_DIR}/${LIB})
######################################################################################
### 3) Define your target(s): just an executable here

View file

@ -3,16 +3,16 @@
##########################################################################################
IF (DOXYGEN_FOUND)
SET(DOC_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "EO documentation directory")
SET(EO_DOC_CONFIG_FILE "eo.cfg" CACHE PATH "EO documentation configuration file")
SET(EO_DOC_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "EO documentation directory" FORCE)
SET(EO_DOC_CONFIG_FILE "eo.doxyfile" CACHE INTERNAL "EO documentation configuration file")
# Copy necessary doc files
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/index.h ${DOC_DIR}/index.h COPYONLY)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/index.h ${EO_DOC_DIR}/index.h COPYONLY)
FILE(GLOB header_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.htm*)
FILE(GLOB pdf_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.pdf)
FILE(GLOB jpg_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.jpg)
FOREACH (file ${header_files} ${pdf_files} ${jpg_files})
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${file} ${DOC_DIR}/${file} COPYONLY)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${file} ${EO_DOC_DIR}/${file} COPYONLY)
ENDFOREACH (file)
# define the doc target

View file

@ -31,8 +31,16 @@ def uninstall():
print('All symlinks have been removed.')
def install():
for dirname in DATA['dirs']: os.mkdir(dirname)
for src, dst in DATA['links']: os.symlink(src, dst)
for dirname in DATA['dirs']:
try:
os.makedirs(dirname)
except(os.error):
pass
for src, dst in DATA['links']:
try:
os.symlink(src, dst)
except:
pass
print('All symlinks have been installed.')
def data():

View file

@ -2,16 +2,16 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Define the eo target
######################################################################################
SET(EO_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
SET(LIBRARY_OUTPUT_PATH ${EO_LIB_OUTPUT_PATH})
set(EO_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib)
set(LIBRARY_OUTPUT_PATH ${EO_LIB_OUTPUT_PATH})
SET(EO_SOURCES
set(EO_SOURCES
eoFunctorStore.cpp
eoPersistent.cpp
eoPrintable.cpp
@ -20,35 +20,36 @@ SET(EO_SOURCES
eoSIGContinue.cpp
)
ADD_LIBRARY(eo STATIC ${EO_SOURCES})
INSTALL(TARGETS eo ARCHIVE DESTINATION ${LIB} COMPONENT libraries)
FILE(GLOB HDRS *.h eo)
INSTALL(FILES ${HDRS} DESTINATION include${INSTALL_SUB_DIR}/eo COMPONENT headers)
INSTALL(DIRECTORY do es ga gp other utils
DESTINATION include${INSTALL_SUB_DIR}/eo
COMPONENT headers
FILES_MATCHING PATTERN "*.h" PATTERN "checkpointing" PATTERN external_eo
)
add_library(eo STATIC ${EO_SOURCES})
######################################################################################
### 3) Optionnal: define your target(s)'s version: no effect for windows
######################################################################################
SET(EO_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(eo PROPERTIES VERSION "${EO_VERSION}")
set(EO_VERSION ${GLOBAL_VERSION})
set_target_properties(eo PROPERTIES VERSION "${EO_VERSION}")
install(TARGETS eo ARCHIVE DESTINATION local/${LIB} COMPONENT libraries)
file(GLOB HDRS *.h eo)
install(FILES ${HDRS} DESTINATION local/include${INSTALL_SUB_DIR}/eo COMPONENT headers)
install(DIRECTORY do es ga gp other utils
DESTINATION local/include${INSTALL_SUB_DIR}/eo
COMPONENT headers
FILES_MATCHING PATTERN "*.h" PATTERN "checkpointing" PATTERN external_eo
)
######################################################################################
### 4) Where must cmake go now ?
######################################################################################
ADD_SUBDIRECTORY(es)
ADD_SUBDIRECTORY(ga)
ADD_SUBDIRECTORY(utils)
add_subdirectory(es)
add_subdirectory(ga)
add_subdirectory(utils)
IF(ENABLE_PYEO)
ADD_SUBDIRECTORY(pyeo)
ENDIF(ENABLE_PYEO)
if(ENABLE_PYEO)
add_subdirectory(pyeo)
endif(ENABLE_PYEO)
######################################################################################

View file

@ -19,7 +19,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: todos@geneura.ugr.es, http://geneura.ugr.es
mak@dhi.dk
mak@dhi.dk
*/
//-----------------------------------------------------------------------------
@ -31,7 +31,10 @@
#include <utils/eoLogger.h>
#include <eoFunctor.h>
#include <vector>
#ifdef _OPENMP
#include <omp.h>
#endif
/**
Applies a unary function to a std::vector of things.
@ -48,29 +51,41 @@ void apply(eoUF<EOT&, void>& _proc, std::vector<EOT>& _pop)
double t1 = 0;
if ( eo::parallel.enableResults() )
{
t1 = omp_get_wtime();
}
{
t1 = omp_get_wtime();
}
if (!eo::parallel.isDynamic())
{
{
#pragma omp parallel for if(eo::parallel.isEnabled()) //default(none) shared(_proc, _pop, size)
for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); }
}
#ifdef _MSC_VER
//Visual Studio supports only OpenMP version 2.0 in which
//an index variable must be of a signed integral type
for (long long i = 0; i < size; ++i) { _proc(_pop[i]); }
#else // _MSC_VER
for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); }
#endif
}
else
{
{
#pragma omp parallel for schedule(dynamic) if(eo::parallel.isEnabled())
//doesnot work with gcc 4.1.2
//default(none) shared(_proc, _pop, size)
for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); }
}
#ifdef _MSC_VER
//Visual Studio supports only OpenMP version 2.0 in which
//an index variable must be of a signed integral type
for (long long i = 0; i < size; ++i) { _proc(_pop[i]); }
#else // _MSC_VER
//doesnot work with gcc 4.1.2
//default(none) shared(_proc, _pop, size)
for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); }
#endif
}
if ( eo::parallel.enableResults() )
{
double t2 = omp_get_wtime();
eoLogger log;
log << eo::file(eo::parallel.prefix()) << t2 - t1 << ' ';
}
{
double t2 = omp_get_wtime();
eoLogger log;
log << eo::file(eo::parallel.prefix()) << t2 - t1 << ' ';
}
#else // _OPENMP
@ -94,7 +109,7 @@ void apply(eoUF<EOT&, void>& _proc, std::vector<EOT>& _pop)
// //default(none) shared(_proc, _pop, size)
// for (size_t i = 0; i < size; ++i)
// {
// _proc(_pop[i]);
// _proc(_pop[i]);
// }
// }
@ -112,7 +127,7 @@ void apply(eoUF<EOT&, void>& _proc, std::vector<EOT>& _pop)
// //default(none) shared(_proc, _pop, size)
// for (size_t i = 0; i < size; ++i)
// {
// _proc(_pop[i]);
// _proc(_pop[i]);
// }
// }

View file

@ -201,7 +201,7 @@ eoCheckPoint<EOT>& do_make_checkpoint(eoParser& _parser, eoState& _state, eoValu
// The Stdout monitor will print parameters to the screen ...
if ( needStdoutMonitor )
{
eoStdoutMonitor *monitor = new eoStdoutMonitor(false);
eoStdoutMonitor *monitor = new eoStdoutMonitor(/*false FIXME remove this deprecated prototype*/);
_state.storeFunctor(monitor);
// when called by the checkpoint (i.e. at every generation)

View file

@ -175,7 +175,7 @@ eoCheckPoint<EOT>& do_make_checkpoint(eoParser& _parser, eoState& _state, eoEval
// The Stdout monitor will print parameters to the screen ...
if ( needStdoutMonitor )
{
eoStdoutMonitor *monitor = new eoStdoutMonitor(false);
eoStdoutMonitor *monitor = new eoStdoutMonitor(/*false FIXME remove this deprecated prototype*/);
_state.storeFunctor(monitor);
// when called by the checkpoint (i.e. at every generation)

View file

@ -129,7 +129,7 @@ eoCheckPoint<EOT>& do_make_checkpoint_assembled(eoParser& _parser, eoState& _sta
// STDOUT
// ------
eoStdoutMonitor *monitor = new eoStdoutMonitor(false);
eoStdoutMonitor *monitor = new eoStdoutMonitor(/*false FIXME remove this deprecated prototype*/);
_state.storeFunctor(monitor);
checkpoint->add(*monitor);
monitor->add(*generationCounter);

View file

@ -78,6 +78,7 @@
#include <eoEvalCounterThrowException.h>
#include <eoEvalTimeThrowException.h>
#include <eoEvalUserTimeThrowException.h>
#include <eoEvalKeepBest.h>
// Continuators - all include eoContinue.h
#include <eoCombinedContinue.h>
@ -102,6 +103,7 @@
#include <eoSharingSelect.h>
// Embedding truncation selection
#include <eoTruncatedSelectOne.h>
#include <eoRankMuSelect.h>
// the batch selection - from an eoSelectOne
#include <eoSelectPerc.h>
@ -141,6 +143,9 @@
#include <utils/eoRealVectorBounds.h> // includes eoRealBounds.h
#include <utils/eoIntBounds.h> // no eoIntVectorBounds
// Serialization stuff
#include <serial/eoSerial.h>
// aliens
#include <other/external_eo>
#include <eoCounter.h>

View file

@ -57,6 +57,7 @@ public:
{
}
/* FIXME remove in next release
/// Ctor - for historical reasons ... should disspear some day
eoCombinedContinue( eoContinue<EOT>& _cont1, eoContinue<EOT>& _cont2)
: eoContinue<EOT>(), std::vector<eoContinue<EOT>* >()
@ -68,12 +69,14 @@ public:
this->push_back(&_cont1);
this->push_back(&_cont2);
}
*/
void add(eoContinue<EOT> & _cont)
{
this->push_back(&_cont);
}
/* FIXME remove in next release
void removeLast(void)
{
#ifndef DEPRECATED_MESSAGES
@ -82,6 +85,7 @@ public:
this->pop_back();
}
*/
/** Returns false when one of the embedded continuators say so (logical and)

View file

@ -44,11 +44,13 @@ public:
rates.push_back(_rate);
}
/* FIXME remove in next release
void add(eoInit<EOT> & _init, double _rate, bool _verbose)
{
eo::log << eo::warnings << "WARNING: the use of the verbose parameter in eoCombinedInit::add is deprecated and will be removed in the next release." << std::endl;
add( _init, _rate );
}
*/
/** The usual method to add objects to the combination
*/

View file

@ -67,4 +67,43 @@ public:
}
};
/**
* Termination condition with a count condition (totalGenerations). This continuator contains
* a count of cycles, which can be retrieved or set.
*
* @ingroup Continuators
* @ingroup Core
*/
template< class EOT >
class eoCountContinue : public eoContinue< EOT >
{
public:
eoCountContinue( ) :
thisGenerationPlaceholder( 0 ),
thisGeneration( thisGenerationPlaceholder )
{
// empty
}
eoCountContinue( unsigned long& currentGen ) :
thisGenerationPlaceholder( 0 ),
thisGeneration( currentGen )
{
// empty
}
virtual std::string className( void ) const { return "eoCountContinue"; }
virtual void reset( )
{
thisGeneration = 0;
}
protected:
unsigned long thisGenerationPlaceholder;
unsigned long& thisGeneration;
};
#endif

View file

@ -34,7 +34,7 @@
#include <math.h>
//-----------------------------------------------------------------------------
/** eoDetSelect selects many individuals determinisctically
/** eoDetSelect selects many individuals deterministically
*
* @ingroup Selectors
*/

View file

@ -37,8 +37,6 @@
#include <eoMergeReduce.h>
#include <eoReplacement.h>
template <class EOT> class eoIslandsEasyEA ;
template <class EOT> class eoDistEvalEasyEA ;
@ -102,6 +100,33 @@ template<class EOT> class eoEasyEA: public eoAlgo<EOT>
offspring.reserve(_offspringSize); // This line avoids an incremental resize of offsprings.
}
/**
* @brief Ctor allowing to specify which pop eval function we're going to use.
*
* Ctor taking a breed and merge, an overload of ctor to define an offspring size, and
* the pop eval function used. This allows to precise if we would like to use the
* parallel evaluation, for instance.
*/
eoEasyEA(
eoContinue<EOT>& _continuator,
eoEvalFunc<EOT>& _eval,
eoPopEvalFunc<EOT>& _pop_eval,
eoBreed<EOT>& _breed,
eoReplacement<EOT>& _replace,
unsigned _offspringSize
) : continuator(_continuator),
eval (_eval),
loopEval(_eval),
popEval(_pop_eval),
selectTransform(dummySelect, dummyTransform),
breed(_breed),
mergeReduce(dummyMerge, dummyReduce),
replace(_replace),
isFirstCall(true)
{
offspring.reserve(_offspringSize); // This line avoids an incremental resize of offsprings.
}
/*
eoEasyEA(eoContinue <EOT> & _continuator,
eoPopEvalFunc <EOT> & _pop_eval,
@ -219,45 +244,44 @@ template<class EOT> class eoEasyEA: public eoAlgo<EOT>
/// Apply a few generation of evolution to the population.
virtual void operator()(eoPop<EOT>& _pop)
{
if (isFirstCall)
{
size_t total_capacity = _pop.capacity() + offspring.capacity();
_pop.reserve(total_capacity);
offspring.reserve(total_capacity);
isFirstCall = false;
}
eoPop<EOT> empty_pop;
popEval(empty_pop, _pop); // A first eval of pop.
do
if (isFirstCall)
{
try
size_t total_capacity = _pop.capacity() + offspring.capacity();
_pop.reserve(total_capacity);
offspring.reserve(total_capacity);
isFirstCall = false;
}
eoPop<EOT> empty_pop;
do
{
try
{
unsigned pSize = _pop.size();
offspring.clear(); // new offspring
unsigned pSize = _pop.size();
breed(_pop, offspring);
offspring.clear(); // new offspring
popEval(_pop, offspring); // eval of parents + offspring if necessary
breed(_pop, offspring);
replace(_pop, offspring); // after replace, the new pop. is in _pop
popEval(_pop, offspring); // eval of parents + offspring if necessary
if (pSize > _pop.size())
throw std::runtime_error("Population shrinking!");
else if (pSize < _pop.size())
throw std::runtime_error("Population growing!");
replace(_pop, offspring); // after replace, the new pop. is in _pop
if (pSize > _pop.size())
throw std::runtime_error("Population shrinking!");
else if (pSize < _pop.size())
throw std::runtime_error("Population growing!");
}
catch (std::exception& e)
catch (std::exception& e)
{
std::string s = e.what();
s.append( " in eoEasyEA");
throw std::runtime_error( s );
std::string s = e.what();
s.append( " in eoEasyEA");
throw std::runtime_error( s );
}
}
while ( continuator( _pop ) );
while ( continuator( _pop ) );
}
protected :

134
eo/src/eoEvalDump.h Normal file
View file

@ -0,0 +1,134 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
© 2012 Thales group
Authors:
Johann Dreo <johann.dreo@thalesgroup.com>
*/
#ifndef eoEvalDump_H
#define eoEvalDump_H
#include <fstream>
#include <eoEvalFunc.h>
/**
Dump an evaluated individual to a given file.
Note: test if the file could be open only in debug mode
If the file cannot be open during the calls, everything will fail in an standard exception.
The file name should be given at instanciation, if you asked for a single file, it will
erase the previously written one and write the new individual in it.
If you do not ask for a single file, it will create several files,
one different each time it found a individual. The filenames have then the form:
<filename><count_prefix><count>
"<count>" being a integer, incremented by one each time a new file is written down.
If you asked for a filename="RESULT", by default, the first dump file will be named "RESULT.0".
*/
template<class EOT>
class eoEvalDump : public eoEvalFunc<EOT>
{
public:
//! A constructor for wrapping your own evaluator in a eoEvalDump.
eoEvalDump(
eoEvalFunc<EOT>& func, std::string filename, bool single_file = false,
unsigned int file_count = 0, std::string count_prefix = "."
) :
_func(func),
_filename(filename), _single_file(single_file), _file_count(file_count), _sep(count_prefix),
_of()
{}
//! A constructor without an eval func, the eoEvalDump will thus just write to the file, without evaluating
eoEvalDump(
std::string filename, bool single_file = false,
unsigned int file_count = 0, std::string count_prefix = "."
) :
_dummy_eval(), _func(_dummy_eval),
_filename(filename), _single_file(single_file), _file_count(file_count), _sep(count_prefix),
_of()
{}
virtual void operator()(EOT& sol)
{
_func( sol );
dump(sol);
}
unsigned int file_count() { return _file_count; }
protected:
// FIXME on x86-64, when called inside a ofstream::open, this function call returns a corrupted string !??
/*
const char * filename()
{
if( _single_file ) {
return _filename.c_str();
} else {
std::ostringstream afilename;
afilename << _filename << _sep << _file_count;
return afilename.str().c_str();
}
}
*/
void dump( EOT & sol )
{
if( _single_file ) {
// explicitely erase the file before writing in it
_of.open( _filename.c_str(), std::ios_base::out | std::ios_base::trunc );
} else {
std::ostringstream afilename;
afilename << _filename << _sep << _file_count;
_of.open( afilename.str().c_str() /* NOTE : defaults to : , std::ios_base::out | std::ios_base::trunc */);
}
#ifndef NDEBUG
if ( !_of.is_open() ) {
std::string str = "Error, eoEvalDump could not open: " + _filename;
throw std::runtime_error( str );
}
#endif
// here, in release mode, we assume that the file could be opened
// thus, we avoid a supplementary test in this costly evaluator
_of << sol << std::endl;
_of.close();
_file_count++;
}
protected:
class DummyEval : public eoEvalFunc<EOT>
{
void operator()(EOT& sol) {/*empty*/}
};
DummyEval _dummy_eval;
eoEvalFunc<EOT>& _func;
std::string _filename;
bool _single_file;
unsigned int _file_count;
std::string _sep;
std::ofstream _of;
};
#endif // eoEvalDump_H

153
eo/src/eoEvalKeepBest.h Normal file
View file

@ -0,0 +1,153 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
© 2012 Thales group
Authors:
Johann Dreo <johann.dreo@thalesgroup.com>
*/
#ifndef eoEvalKeepBest_H
#define eoEvalKeepBest_H
#include <fstream>
#include <eoEvalFunc.h>
#include <utils/eoParam.h>
/**
Evaluate with the given evaluator and keep the best individual found so far.
This is useful if you use a non-monotonic algorithm, such as CMA-ES, where the
population's best fitness can decrease between two generations. This is
sometime necessary and one can't use elitist replacors, as one do not want to
introduce a bias in the population.
The eoEvalBestKeep can be used as a wrapper around a classical evaluator,
that keep the best individual it has found since its instanciation.
To get the best individual, you have to call best_element() on the
eoEvalKeepBest itself, and not on the population (or else you would get the
best individual found at the last generation).
Example:
MyEval true_eval;
eoEvalKeepBest<T> wrapped_eval( true_eval );
// as an interesting side effect, you will get the best individual since
// initalization.
eoPop<T> pop( my_init );
eoPopLoopEval<T> loop_eval( wrapped_eval );
loop_eval( pop );
eoEasyEA algo( , wrapped_eval, );
algo(pop);
// do not use pop.best_element()!
std::cout << wrapped_eval.best_element() << std::endl;
You can also inherits from eoEvalKeepBest, if you want to add its interface
with your own one. But then, you will have to explicitely call the base class
functor:
class MyEval : public eoEvalKeepBest<EOT>
{
MyEval() : eoEvalKeepBest<EOT>() {}
virtual void operator()(EOT& sol)
{
// evaluate sol here
// ...
// keep the best
eoEvalKeepBest<EOT>::operator()( sol );
};
@ingroup Evaluation
*/
template<class EOT> class eoEvalKeepBest : public eoEvalFunc<EOT>, public eoValueParam<EOT>
{
public :
/** A constructor for inheritance: if you want to inherit from eoEvalKeepBest.
*
* Keep in mind that you will have to call eoEvalKeepBest in your own implementation of operator().
*
* This constructor uses a dummy evaluator.
*/
eoEvalKeepBest( std::string _name = "VeryBest. " )
: eoValueParam<EOT>(EOT(), _name), dummy_eval(), func(dummy_eval), _found(false) {}
/** A constructor for wrapping your own evaluator in a eoEvalKeepBest.
*/
eoEvalKeepBest(eoEvalFunc<EOT>& _func, std::string _name = "VeryBest. ")
: eoValueParam<EOT>(EOT(), _name), dummy_eval(), func(_func), _found(false) {}
virtual void operator()(EOT& sol)
{
_found = false;
func(sol); // evaluate
assert( ! sol.invalid() );
// if there is no best kept
if( this->value().invalid() ) {
// FIXME replace this test by a reference fitness passed at instanciation
// take the first individual as best
this->value() = sol;
} else {
// if sol is better than the kept individual
if( sol.fitness() > this->value().fitness() ) {
this->value() = sol;
_found = true;
}
}
}
//! Return the best individual found so far.
EOT best_element()
{
return this->value();
}
/** Reset the best individual to the given one. If no individual is
* provided, the next evaluated one will be taken as a reference.
*/
void reset( const EOT& new_best = EOT() )
{
this->value() = new_best;
}
//! Tell if a best individual has been found during the last call
bool found() const
{
return _found;
}
class DummyEval : public eoEvalFunc<EOT>
{
void operator()(EOT& sol) {/*empty*/}
};
protected :
DummyEval dummy_eval;
eoEvalFunc<EOT>& func;
bool _found;
};
#endif

View file

@ -21,28 +21,30 @@ Authors:
Johann Dréo <johann.dreo@thalesgroup.com>
*/
#ifndef __unix__
/*#warning "Warning: class 'eoEvalUserTimeThrowException' is only available under UNIX systems (defining 'rusage' in 'sys/resource.h'), contributions for other systems are welcomed."*/
#else
#if !defined(__unix__) && !defined(_WINDOWS)
#warning "Warning: class 'eoEvalUserTimeThrowException' is only available under UNIX (defining 'rusage' in 'sys/resource.h') or Win32 (defining 'GetProcessTimes' in 'WinBase.h') systems, contributions for other systems are welcomed."
#else //!defined(__unix__) && !defined(_WINDOWS)
#ifndef __EOEVALUSERTIMETHROWEXCEPTION_H__
#define __EOEVALUSERTIMETHROWEXCEPTION_H__
#include <sys/time.h>
#include <sys/resource.h>
#include <eoExceptions.h>
/** Check at each evaluation if a given CPU user time contract has been reached.
*
* Throw an eoMaxTimeException if the given max time has been reached.
* Usefull if you want to end the search independently of generations.
* This class uses (almost-)POSIX headers.
* This class uses (almost-)POSIX or Win32 headers, depending on the platform.
* It uses a computation of the user time used on the CPU. For a wallclock time measure, see eoEvalTimeThrowException
*
* @ingroup Evaluation
*/
#include <eoExceptions.h>
#ifdef __unix__
#include <sys/time.h>
#include <sys/resource.h>
template< class EOT >
class eoEvalUserTimeThrowException : public eoEvalFuncCounter< EOT >
{
@ -59,7 +61,7 @@ public:
if( current >= _max ) {
throw eoMaxTimeException( current );
} else {
func(eo);
this->func(eo);
}
}
}
@ -69,5 +71,41 @@ protected:
struct rusage _usage;
};
#else
#ifdef _WINDOWS
//here _WINDOWS is defined
#include <WinBase.h>
template< class EOT >
class eoEvalUserTimeThrowException : public eoEvalFuncCounter< EOT >
{
public:
eoEvalUserTimeThrowException( eoEvalFunc<EOT> & func, const long max ) : eoEvalFuncCounter<EOT>( func, "CPU-user"), _max(max) {}
virtual void operator() ( EOT & eo )
{
if( eo.invalid() ) {
FILETIME dummy;
GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, &dummy, &_usage);
ULARGE_INTEGER current;
current.LowPart = _usage.dwLowDateTime;
current.HighPart = _usage.dwHighDateTime;
if( current.QuadPart >= _max ) {
throw eoMaxTimeException( current.QuadPart );
} else {
func(eo);
}
}
}
protected:
const long _max;
FILETIME _usage;
};
#endif // _WINDOWS
#endif //__unix__
#endif // __EOEVALUSERTIMETHROWEXCEPTION_H__
#endif // __UNIX__
#endif //!defined(__unix__) && !defined(_WINDOWS)

View file

@ -28,6 +28,9 @@
#define _eoFunctorStore_h
#include <vector>
#include<algorithm>
#include "utils/eoLogger.h"
class eoFunctorBase;
@ -52,6 +55,13 @@ public:
template <class Functor>
Functor& storeFunctor(Functor* r)
{
#ifndef NDEBUG
unsigned int existing = std::count( vec.begin(), vec.end(), r );
if( existing > 0 ) {
eo::log << eo::warnings << "WARNING: you asked eoFunctorStore to store the functor " << r << " "
<< existing + 1 << " times, a segmentation fault may occur in the destructor." << std::endl;
}
#endif
// If the compiler complains about the following line,
// check if you really are giving it a pointer to an
// eoFunctorBase derived object
@ -67,6 +77,7 @@ private :
/** no assignment allowed */
eoFunctorStore operator=(const eoFunctorStore&);
protected:
std::vector<eoFunctorBase*> vec;
};

View file

@ -35,24 +35,24 @@
@ingroup Continuators
*/
template< class EOT>
class eoGenContinue: public eoContinue<EOT>, public eoValueParam<unsigned>
class eoGenContinue: public eoCountContinue<EOT>, public eoValueParam<unsigned>
{
public:
using eoCountContinue<EOT>::thisGeneration;
using eoCountContinue<EOT>::thisGenerationPlaceholder;
/// Ctor for setting a
eoGenContinue( unsigned long _totalGens)
: eoValueParam<unsigned>(0, "Generations", "Generations"),
repTotalGenerations( _totalGens ),
thisGenerationPlaceHolder(0),
thisGeneration(thisGenerationPlaceHolder)
: eoCountContinue<EOT>( ),
eoValueParam<unsigned>(0, "Generations", "Generations"),
repTotalGenerations( _totalGens )
{};
/// Ctor for enabling the save/load the no. of generations counted
eoGenContinue( unsigned long _totalGens, unsigned long& _currentGen)
: eoValueParam<unsigned>(0, "Generations", "Generations"),
repTotalGenerations( _totalGens ),
thisGenerationPlaceHolder(0),
thisGeneration(_currentGen)
: eoCountContinue<EOT>( _currentGen ), eoValueParam<unsigned>(0, "Generations", "Generations"),
repTotalGenerations( _totalGens )
{};
/** Returns false when a certain number of generations is
@ -77,7 +77,7 @@ public:
*/
virtual void totalGenerations( unsigned long _tg ) {
repTotalGenerations = _tg;
thisGeneration = 0;
eoCountContinue<EOT>::reset();
};
/** Returns the number of generations to reach*/
@ -86,7 +86,6 @@ public:
return repTotalGenerations;
};
virtual std::string className(void) const { return "eoGenContinue"; }
/** Read from a stream
@ -107,8 +106,6 @@ public:
private:
unsigned long repTotalGenerations;
unsigned long thisGenerationPlaceHolder;
unsigned long& thisGeneration;
};
#endif

View file

@ -55,7 +55,7 @@ class eoMergeReduce : public eoReplacement<EOT>
merge(_merge), reduce(_reduce)
{}
void operator()(eoPop<EOT>& _parents, eoPop<EOT>& _offspring)
virtual void operator()(eoPop<EOT>& _parents, eoPop<EOT>& _offspring)
{
merge(_parents, _offspring); // parents untouched, result in offspring
reduce(_offspring, _parents.size());
@ -92,6 +92,14 @@ class eoCommaReplacement : public eoMergeReduce<EOT>
public :
eoCommaReplacement() : eoMergeReduce<EOT>(no_elite, truncate) {}
virtual void operator()(eoPop<EOT>& _parents, eoPop<EOT>& _offspring)
{
// There must be more offsprings than parents, or else an exception will be raised
assert( _offspring.size() >= _parents.size() );
eoMergeReduce<EOT>::operator()( _parents, _offspring );
}
private :
eoNoElitism<EOT> no_elite;
eoTruncate<EOT> truncate;

View file

@ -4,31 +4,41 @@
// eoPop.h
// (c) GeNeura Team, 1998
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: todos@geneura.ugr.es, http://geneura.ugr.es
*/
Authors:
todos@geneura.ugr.es, http://geneura.ugr.es
jmerelo
gustavoromero
mac
maartenkeijzer
kuepper
okoenig
evomarc
Johann Dréo <johann.dreo@thalesgroup.com>
*/
//-----------------------------------------------------------------------------
#ifndef _EOPOP_H
#define _EOPOP_H
#ifndef _EOPOP_H_
#define _EOPOP_H_
#include <algorithm>
#include <iostream>
#include <iterator> // needed for GCC 3.2
#include <vector>
#include <assert.h>
// EO includes
#include <eoOp.h> // for eoInit
@ -54,18 +64,18 @@
template<class EOT>
class eoPop: public std::vector<EOT>, public eoObject, public eoPersistent
{
public:
public:
using std::vector<EOT>::size;
using std::vector<EOT>::resize;
using std::vector<EOT>::operator[];
using std::vector<EOT>::begin;
using std::vector<EOT>::end;
using std::vector<EOT>::size;
using std::vector<EOT>::resize;
using std::vector<EOT>::operator[];
using std::vector<EOT>::begin;
using std::vector<EOT>::end;
typedef typename EOT::Fitness Fitness;
typedef typename EOT::Fitness Fitness;
#if defined(__CUDACC__)
typedef typename std::vector<EOT>::iterator iterator;
typedef typename std::vector<EOT>::const_iterator const_iterator;
typedef typename std::vector<EOT>::iterator iterator;
typedef typename std::vector<EOT>::const_iterator const_iterator;
#endif
/** Default ctor. Creates empty pop
@ -74,266 +84,297 @@ public:
/** Ctor for the initialization of chromosomes
@param _popSize total population size
@param _chromInit Initialization routine, produces EO's, needs to be an eoInit
@param _popSize total population size
@param _chromInit Initialization routine, produces EO's, needs to be an eoInit
*/
eoPop( unsigned _popSize, eoInit<EOT>& _chromInit )
:std::vector<EOT>()
{
resize(_popSize);
for ( unsigned i = 0; i < _popSize; i++ )
{
eoPop( unsigned _popSize, eoInit<EOT>& _chromInit )
: std::vector<EOT>()
{
resize(_popSize);
for ( unsigned i = 0; i < _popSize; i++ )
{
_chromInit(operator[](i));
}
};
}
}
/** appends random guys at end of pop.
Can be used to initialize it pop is empty
Can be used to initialize it pop is empty
@param _newPopSize total population size
@param _chromInit Initialization routine, produces EO's, needs to be an eoInit
@param _newPopSize total population size
@param _chromInit Initialization routine, produces EO's, needs to be an eoInit
*/
void append( unsigned _newPopSize, eoInit<EOT>& _chromInit )
{
unsigned oldSize = size();
if (_newPopSize < oldSize)
void append( unsigned _newPopSize, eoInit<EOT>& _chromInit )
{
throw std::runtime_error("New size smaller than old size in pop.append");
return;
unsigned oldSize = size();
if (_newPopSize < oldSize)
{
throw std::runtime_error("New size smaller than old size in pop.append");
return;
}
if (_newPopSize == oldSize)
return;
resize(_newPopSize); // adjust the size
for ( unsigned i = oldSize; i < _newPopSize; i++ )
{
_chromInit(operator[](i));
}
}
if (_newPopSize == oldSize)
return;
resize(_newPopSize); // adjust the size
for ( unsigned i = oldSize; i < _newPopSize; i++ )
/** Ctor from an std::istream; reads the population from a stream,
each element should be in different lines
@param _is the stream
*/
eoPop( std::istream& _is ) :std::vector<EOT>()
{
_chromInit(operator[](i));
readFrom( _is );
}
};
/** Ctor from an std::istream; reads the population from a stream,
each element should be in different lines
@param _is the stream
*/
eoPop( std::istream& _is ) :std::vector<EOT>() {
readFrom( _is );
}
/** Empty Dtor */
/** Empty Dtor */
virtual ~eoPop() {}
/// helper struct for getting a pointer
struct Ref { const EOT* operator()(const EOT& eot) { return &eot;}};
/// helper struct for comparing on pointers
struct Cmp {
bool operator()(const EOT* a, const EOT* b) const
/// helper struct for getting a pointer
struct Ref { const EOT* operator()(const EOT& eot) { return &eot;}};
/// helper struct for comparing on pointers
struct Cmp {
bool operator()(const EOT* a, const EOT* b) const
{ return b->operator<(*a); }
};
/// helper struct for comparing (EA or PSO)
struct Cmp2
{
bool operator()(const EOT & a,const EOT & b) const
};
/// helper struct for comparing (EA or PSO)
struct Cmp2
{
bool operator()(const EOT & a,const EOT & b) const
{
return b.operator<(a);
}
};
/**
sort the population. Use this member to sort in order
of descending Fitness, so the first individual is the best!
*/
void sort(void)
{
std::sort(begin(), end(), Cmp2());
}
};
/** creates a std::vector<EOT*> pointing to the individuals in descending order */
void sort(std::vector<const EOT*>& result) const
{
result.resize(size());
/**
sort the population. Use this member to sort in order
of descending Fitness, so the first individual is the best!
*/
void sort(void)
{
std::sort(begin(), end(), Cmp2());
}
std::transform(begin(), end(), result.begin(), Ref());
/** creates a std::vector<EOT*> pointing to the individuals in descending order */
void sort(std::vector<const EOT*>& result) const
{
result.resize(size());
std::sort(result.begin(), result.end(), Cmp());
}
std::transform(begin(), end(), result.begin(), Ref());
std::sort(result.begin(), result.end(), Cmp());
}
/**
shuffle the population. Use this member to put the population
in random order
*/
void shuffle(void)
{
UF_random_generator<unsigned int> gen;
std::random_shuffle(begin(), end(), gen);
}
/**
shuffle the population. Use this member to put the population
in random order
*/
void shuffle(void)
{
UF_random_generator<unsigned int> gen;
std::random_shuffle(begin(), end(), gen);
}
/** creates a std::vector<EOT*> pointing to the individuals in random order */
void shuffle(std::vector<const EOT*>& result) const
{
result.resize(size());
/** creates a std::vector<EOT*> pointing to the individuals in random order */
void shuffle(std::vector<const EOT*>& result) const
{
result.resize(size());
std::transform(begin(), end(), result.begin(), Ref());
std::transform(begin(), end(), result.begin(), Ref());
UF_random_generator<unsigned int> gen;
std::random_shuffle(result.begin(), result.end(), gen);
}
UF_random_generator<unsigned int> gen;
std::random_shuffle(result.begin(), result.end(), gen);
}
/** returns an iterator to the best individual DOES NOT MOVE ANYBODY */
/** returns an iterator to the best individual DOES NOT MOVE ANYBODY */
#if defined(__CUDACC__)
eoPop<EOT>::iterator it_best_element()
{
eoPop<EOT>:: iterator it = std::max_element(begin(), end());
eoPop<EOT>::iterator it_best_element()
{
eoPop<EOT>:: iterator it = std::max_element(begin(), end());
#else
typename eoPop<EOT>::iterator it_best_element() {
typename eoPop<EOT>::iterator it = std::max_element(begin(), end());
typename eoPop<EOT>::iterator it_best_element()
{
assert( this->size() > 0 );
typename eoPop<EOT>::iterator it = std::max_element(begin(), end());
#endif
return it;
}
return it;
}
/** returns an iterator to the best individual DOES NOT MOVE ANYBODY */
const EOT & best_element() const
{
/** returns an iterator to the best individual DOES NOT MOVE ANYBODY */
const EOT & best_element() const
{
#if defined(__CUDACC__)
eoPop<EOT>::const_iterator it = std::max_element(begin(), end());
eoPop<EOT>::const_iterator it = std::max_element(begin(), end());
#else
typename eoPop<EOT>::const_iterator it = std::max_element(begin(), end());
typename eoPop<EOT>::const_iterator it = std::max_element(begin(), end());
#endif
return (*it);
}
if( it == end() )
throw std::runtime_error("eoPop<EOT>: Empty population, when calling best_element().");
return (*it);
}
/** returns a const reference to the worse individual DOES NOT MOVE ANYBODY */
const EOT & worse_element() const
{
/** returns a const reference to the worse individual DOES NOT MOVE ANYBODY */
const EOT & worse_element() const
{
#if defined(__CUDACC__)
eoPop<EOT>::const_iterator it = std::min_element(begin(), end());
eoPop<EOT>::const_iterator it = std::min_element(begin(), end());
#else
typename eoPop<EOT>::const_iterator it = std::min_element(begin(), end());
assert( this->size() > 0 );
typename eoPop<EOT>::const_iterator it = std::min_element(begin(), end());
#endif
return (*it);
}
return (*it);
}
/** returns an iterator to the worse individual DOES NOT MOVE ANYBODY */
/** returns an iterator to the worse individual DOES NOT MOVE ANYBODY */
#if defined(__CUDACC__)
eoPop<EOT>::iterator it_worse_element()
{
eoPop<EOT>::iterator it = std::min_element(begin(), end());
eoPop<EOT>::iterator it_worse_element()
{
eoPop<EOT>::iterator it = std::min_element(begin(), end());
#else
typename eoPop<EOT>::iterator it_worse_element()
{
typename eoPop<EOT>::iterator it = std::min_element(begin(), end());
typename eoPop<EOT>::iterator it_worse_element()
{
assert( this->size() > 0 );
typename eoPop<EOT>::iterator it = std::min_element(begin(), end());
#endif
return it;
}
return it;
}
/**
slightly faster algorithm than sort to find all individuals that are better
than the nth individual. INDIVIDUALS ARE MOVED AROUND in the pop.
*/
/**
slightly faster algorithm than sort to find all individuals that are better
than the nth individual. INDIVIDUALS ARE MOVED AROUND in the pop.
*/
#if defined(__CUDACC__)
eoPop<EOT>::iterator nth_element(int nth)
{
eoPop<EOT>::iterator it = begin() + nth;
eoPop<EOT>::iterator nth_element(int nth)
{
eoPop<EOT>::iterator it = begin() + nth;
#else
typename eoPop<EOT>::iterator nth_element(int nth)
{
typename eoPop<EOT>::iterator it = begin() + nth;
typename eoPop<EOT>::iterator nth_element(int nth)
{
assert( this->size() > 0 );
typename eoPop<EOT>::iterator it = begin() + nth;
#endif
std::nth_element(begin(), it, end(), std::greater<EOT>());
return it;
}
std::nth_element(begin(), it, end(), std::greater<EOT>());
return it;
}
struct GetFitness { Fitness operator()(const EOT& _eo) const { return _eo.fitness(); } };
/** returns the fitness of the nth element */
Fitness nth_element_fitness(int which) const
{ // probably not the fastest way to do this, but what the heck
struct GetFitness { Fitness operator()(const EOT& _eo) const { return _eo.fitness(); } };
std::vector<Fitness> fitness(size());
std::transform(begin(), end(), fitness.begin(), GetFitness());
typename std::vector<Fitness>::iterator it = fitness.begin() + which;
std::nth_element(fitness.begin(), it, fitness.end(), std::greater<Fitness>());
return *it;
}
/** returns the fitness of the nth element */
Fitness nth_element_fitness(int which) const
{ // probably not the fastest way to do this, but what the heck
/** const nth_element function, returns pointers to sorted individuals
* up the the nth
*/
void nth_element(int which, std::vector<const EOT*>& result) const
{
std::vector<Fitness> fitness(size());
std::transform(begin(), end(), fitness.begin(), GetFitness());
result.resize(size());
std::transform(begin(), end(), result.begin(), Ref());
typename std::vector<Fitness>::iterator it = fitness.begin() + which;
std::nth_element(fitness.begin(), it, fitness.end(), std::greater<Fitness>());
return *it;
}
typename std::vector<const EOT*>::iterator it = result.begin() + which;
std::nth_element(result.begin(), it, result.end(), Cmp());
}
/** const nth_element function, returns pointers to sorted individuals
* up the the nth
*/
void nth_element(int which, std::vector<const EOT*>& result) const
{
/** does STL swap with other pop */
void swap(eoPop<EOT>& other)
{
std::swap(static_cast<std::vector<EOT>& >(*this), static_cast<std::vector<EOT>& >(other));
}
assert( this->size() > 0 );
result.resize(size());
std::transform(begin(), end(), result.begin(), Ref());
/**
* Prints sorted pop but does NOT modify it!
*
* @param _os A std::ostream.
*/
virtual void sortedPrintOn(std::ostream& _os) const
{
std::vector<const EOT*> result;
sort(result);
_os << size() << '\n';
for (unsigned i = 0; i < size(); ++i)
{
_os << *result[i] << std::endl;
}
}
typename std::vector<const EOT*>::iterator it = result.begin() + which;
/**
* Write object. It's called printOn since it prints the object _on_ a stream.
* @param _os A std::ostream.
*/
virtual void printOn(std::ostream& _os) const
{
_os << size() << '\n';
std::copy( begin(), end(), std::ostream_iterator<EOT>( _os, "\n") );
}
std::nth_element(result.begin(), it, result.end(), Cmp());
}
/** @name Methods from eoObject */
//@{
/**
* Read object. The EOT class must have a ctor from a stream;
* @param _is A std::istream.
*/
virtual void readFrom(std::istream& _is)
{
size_t sz;
_is >> sz;
resize(sz);
/** does STL swap with other pop */
void swap(eoPop<EOT>& other)
{
std::swap(static_cast<std::vector<EOT>& >(*this), static_cast<std::vector<EOT>& >(other));
}
for (size_t i = 0; i < sz; ++i) {
operator[](i).readFrom( _is );
}
}
/** Inherited from eoObject. Returns the class name.
@see eoObject
*/
virtual std::string className() const {return "eoPop";};
//@}
/**
* Prints sorted pop but does NOT modify it!
*
* @param _os A std::ostream.
*/
virtual void sortedPrintOn(std::ostream& _os) const
{
std::vector<const EOT*> result;
sort(result);
_os << size() << '\n';
for (unsigned i = 0; i < size(); ++i)
{
_os << *result[i] << std::endl;
}
}
virtual void invalidate()
{
for (unsigned i=0; i<size(); i++)
this->operator[](i).invalidate();
}
};
#endif
/**
* Write object. It's called printOn since it prints the object _on_ a stream.
* @param _os A std::ostream.
*/
virtual void printOn(std::ostream& _os) const
{
_os << size() << '\n';
std::copy( begin(), end(), std::ostream_iterator<EOT>( _os, "\n") );
}
/** @name Methods from eoObject */
//@{
/**
* Read object. The EOT class must have a ctor from a stream;
* @param _is A std::istream.
*/
virtual void readFrom(std::istream& _is)
{
size_t sz;
_is >> sz;
resize(sz);
for (size_t i = 0; i < sz; ++i) {
operator[](i).readFrom( _is );
}
}
/** Inherited from eoObject. Returns the class name.
@see eoObject
*/
virtual std::string className() const {return "eoPop";};
//@}
/** Invalidate the whole population
*/
virtual void invalidate()
{
for (unsigned i=0; i<size(); i++)
this->operator[](i).invalidate();
}
}; // class eoPop
#endif // _EOPOP_H_

View file

@ -30,6 +30,16 @@
#include <eoEvalFunc.h>
#include <apply.h>
# ifdef WITH_MPI
#include <mpi/eoMpi.h>
#include <mpi/eoTerminateJob.h>
#include <mpi/eoMpiAssignmentAlgorithm.h>
#include <mpi/eoParallelApply.h>
#include <utils/eoParallel.h>
#include <cmath> // ceil
# endif // WITH_MPI
/** eoPopEvalFunc: This abstract class is for GLOBAL evaluators
* of a population after variation.
* It takes 2 populations (typically the parents and the offspring)
@ -77,6 +87,142 @@ private:
eoEvalFunc<EOT> & eval;
};
#ifdef WITH_MPI
/**
* @brief Evaluator of a population of EOT which uses parallelization to evaluate individuals.
*
* This class implements an instance of eoPopEvalFunc that applies a private eoEvalFunc to
* all offspring, but in a parallel way. The original process becomes the central host from a network ("master"), and
* other machines disponible in the MPI network ("slaves") are used as evaluators. Population to evaluate is splitted in
* little packets of individuals, which are sent to the evaluators, that process the effective call to eval. Once all
* the individuals have been evaluated, they are returned to the master. The whole process is entirely invisible to the
* eyes of the user, who just has to launch a certain number of processes in MPI so as to have a result.
*
* The eoEvalFunc is no more directly given, but it is stored in the eo::mpi::ParallelApplyStore, which can be
* instanciated if no one is given at construction.
*
* The use of this class requires the user to have called the eo::mpi::Node::init function, at the beginning of its
* program.
*
* @ingroup Evaluation Parallel
*
* @author Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
template<class EOT>
class eoParallelPopLoopEval : public eoPopEvalFunc<EOT>
{
public:
/**
* @brief Constructor which creates the job store for the user.
*
* This constructor is the simplest to use, as it creates the store used by the parallel job, for the user.
* The user just precises the scheduling algorithm, the rank of the master and then gives its eval function and
* the size of a packet (how many individuals should be in a single message to evaluator).
*
* @param _assignAlgo The scheduling algorithm used to give orders to evaluators.
* @param _masterRank The MPI rank of the master.
* @param _eval The evaluation functor used to evaluate each individual in the population.
* @param _packetSize The number of individuals to send in one message to evaluator, and which are evaluated at
* a time.
*/
eoParallelPopLoopEval(
// Job parameters
eo::mpi::AssignmentAlgorithm& _assignAlgo,
int _masterRank,
// Default parameters for store
eoEvalFunc<EOT> & _eval,
int _packetSize = 1
) :
assignAlgo( _assignAlgo ),
masterRank( _masterRank ),
needToDeleteStore( true ) // we used new, we'll have to use delete (RAII)
{
store = new eo::mpi::ParallelApplyStore<EOT>( _eval, _masterRank, _packetSize );
}
/**
* @brief Constructor which allows the user to customize its job store.
*
* This constructor allows the user to customize the store, for instance by adding wrappers and other
* functionnalities, before using it for the parallelized evaluation.
*
* @param _assignAlgo The scheduling algorithm used to give orders to evaluators.
* @param _masterRank The MPI rank of the master.
* @param _store Pointer to a parallel eval store given by the user.
*/
eoParallelPopLoopEval(
// Job parameters
eo::mpi::AssignmentAlgorithm& _assignAlgo,
int _masterRank,
eo::mpi::ParallelApplyStore<EOT>* _store
) :
assignAlgo( _assignAlgo ),
masterRank( _masterRank ),
store( _store ),
needToDeleteStore( false ) // we haven't used new for creating store, we don't care if we have to delete it (RAII).
{
// empty
}
/**
* @brief Default destructor. Sends a message to all evaluators indicating that the global loop (eoEasyEA, for
* instance) is over.
*/
~eoParallelPopLoopEval()
{
// Only the master has to send the termination message
if( eo::mpi::Node::comm().rank() == masterRank )
{
eo::mpi::EmptyJob job( assignAlgo, masterRank );
job.run();
}
// RAII
if( needToDeleteStore )
{
delete store;
}
}
/**
* @brief Parallel implementation of the operator().
*
* @param _parents Population of parents (ignored).
* @param _offspring Population of children, which will be evaluated.
*/
void operator()( eoPop<EOT> & _parents, eoPop<EOT> & _offspring )
{
(void)_parents;
// Reinits the store and the scheduling algorithm
store->data( _offspring );
// For static scheduling, it's mandatory to reinit attributions
int nbWorkers = assignAlgo.availableWorkers();
assignAlgo.reinit( nbWorkers );
if( ! eo::parallel.isDynamic() ) {
store->data()->packetSize = ceil( static_cast<double>( _offspring.size() ) / nbWorkers );
}
// Effectively launches the job.
eo::mpi::ParallelApply<EOT> job( assignAlgo, masterRank, *store );
job.run();
}
private:
// Scheduling algorithm
eo::mpi::AssignmentAlgorithm & assignAlgo;
// Master MPI rank
int masterRank;
// Store
eo::mpi::ParallelApplyStore<EOT>* store;
// Do we have to delete the store by ourselves ?
bool needToDeleteStore;
};
/**
* @example t-mpi-eval.cpp
*/
#endif
/////////////////////////////////////////////////////////////
// eoTimeVaryingLoopEval
/////////////////////////////////////////////////////////////

View file

@ -186,6 +186,7 @@ public:
virtual std::string className() const { return "eoPropCombinedQuadOp"; }
/* FIXME remove in next release
virtual void add(eoQuadOp<EOT> & _op, const double _rate, bool _verbose)
{
#ifndef DEPRECATED_MESSAGES
@ -195,6 +196,7 @@ public:
add(_op,_rate);
}
*/
// addition of a true operator
virtual void add(eoQuadOp<EOT> & _op, const double _rate)
@ -202,7 +204,7 @@ public:
ops.push_back(&_op);
rates.push_back(_rate);
// compute the relative rates in percent - to warn the user!
printOn( eo::log << eo::logging );
printOn( eo::log << eo::logging );
}
// outputs the operators and percentages

54
eo/src/eoRankMuSelect.h Normal file
View file

@ -0,0 +1,54 @@
/*
The Evolving Distribution Objects framework (EDO) is a template-based,
ANSI-C++ evolutionary computation library which helps you to write your
own estimation of distribution algorithms.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 2012 Thales group
*/
/*
Authors:
Johann Dréo <johann.dreo@thalesgroup.com>
*/
#ifndef _eoRankMuSelect_h
#define _eoRankMuSelect_h
#include "eoDetSelect.h"
/** Selects the "Mu" bests individuals.
*
* Note: sorts the population before trucating it.
*
* @ingroup Selectors
*/
template<typename EOT>
class eoRankMuSelect : public eoDetSelect<EOT>
{
public :
// false, because mu is not a rate
eoRankMuSelect( unsigned int mu ) : eoDetSelect<EOT>( mu, false ) {}
void operator()(const eoPop<EOT>& source, eoPop<EOT>& dest)
{
eoPop<EOT> tmp( source );
tmp.sort();
eoDetSelect<EOT>::operator()( tmp, dest );
}
};
#endif // !_eoRankMuselect_h

View file

@ -35,23 +35,26 @@
@ingroup Continuators
*/
template< class EOT>
class eoSteadyFitContinue: public eoContinue<EOT>
class eoSteadyFitContinue: public eoCountContinue<EOT>
{
public:
typedef typename EOT::Fitness Fitness;
using eoCountContinue<EOT>::thisGenerationPlaceholder;
using eoCountContinue<EOT>::thisGeneration;
/// Ctor for setting a
eoSteadyFitContinue( unsigned long _minGens, unsigned long _steadyGens)
: repMinGenerations( _minGens ), repSteadyGenerations( _steadyGens),
steadyState(false), thisGenerationPlaceHolder(0),
thisGeneration(thisGenerationPlaceHolder){};
: eoCountContinue<EOT>( ), repMinGenerations( _minGens ), repSteadyGenerations( _steadyGens),
steadyState(false)
{};
/// Ctor for enabling the save/load the no. of generations counted
eoSteadyFitContinue( unsigned long _minGens, unsigned long _steadyGen,
unsigned long& _currentGen)
: repMinGenerations( _minGens ), repSteadyGenerations( _steadyGen),
steadyState(_currentGen>_minGens), thisGenerationPlaceHolder(0),
thisGeneration(_currentGen){};
: eoCountContinue<EOT>( _currentGen ), repMinGenerations( _minGens ), repSteadyGenerations( _steadyGen),
steadyState(_currentGen>_minGens)
{};
/** Returns false when a certain number of generations is
* reached withtout improvement */
@ -96,7 +99,7 @@ public:
/// Resets the state after it's been reached
virtual void reset () {
steadyState=false;
thisGeneration = 0;
eoCountContinue<EOT>::reset();
}
/** accessors*/
@ -110,8 +113,6 @@ private:
unsigned long repMinGenerations;
unsigned long repSteadyGenerations;
bool steadyState;
unsigned long thisGenerationPlaceHolder;
unsigned long& thisGeneration;
unsigned int lastImprovement;
Fitness bestSoFar;
};

View file

@ -2,19 +2,19 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Define the es and cma targets
######################################################################################
SET(ES_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
SET(CMA_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
set(ES_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib)
set(CMA_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib)
SET(LIBRARY_OUTPUT_PATH ${ES_LIB_OUTPUT_PATH}) # the same output for the two libs
set(LIBRARY_OUTPUT_PATH ${ES_LIB_OUTPUT_PATH}) # the same output for the two libs
SET(ES_SOURCES
set(ES_SOURCES
make_algo_scalar_es.cpp
make_algo_scalar_real.cpp
make_checkpoint_es.cpp
@ -31,26 +31,26 @@ SET(ES_SOURCES
make_run_real.cpp
)
SET(CMA_SOURCES
set(CMA_SOURCES
eig.cpp
CMAState.cpp
CMAParams.cpp
)
ADD_LIBRARY(es STATIC ${ES_SOURCES})
INSTALL(TARGETS es ARCHIVE DESTINATION ${LIB} COMPONENT libraries)
add_library(es STATIC ${ES_SOURCES})
install(TARGETS es ARCHIVE DESTINATION local/${LIB} COMPONENT libraries)
ADD_LIBRARY(cma STATIC ${CMA_SOURCES})
INSTALL(TARGETS cma ARCHIVE DESTINATION ${LIB} COMPONENT libraries)
add_library(cma STATIC ${CMA_SOURCES})
install(TARGETS cma ARCHIVE DESTINATION local/${LIB} COMPONENT libraries)
######################################################################################
### 3) Optionnal
######################################################################################
SET(ES_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(es PROPERTIES VERSION "${ES_VERSION}")
set(ES_VERSION ${GLOBAL_VERSION})
set_target_properties(es PROPERTIES VERSION "${ES_VERSION}")
SET(CMA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(cma PROPERTIES VERSION "${CMA_VERSION}")
set(CMA_VERSION ${GLOBAL_VERSION})
set_target_properties(cma PROPERTIES VERSION "${CMA_VERSION}")
######################################################################################

View file

@ -2,17 +2,17 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Define the ga target
######################################################################################
SET(GA_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
SET(LIBRARY_OUTPUT_PATH ${GA_LIB_OUTPUT_PATH})
set(GA_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib)
set(LIBRARY_OUTPUT_PATH ${GA_LIB_OUTPUT_PATH})
SET(GA_SOURCES
set(GA_SOURCES
make_algo_scalar_ga.cpp
make_checkpoint_ga.cpp
make_continue_ga.cpp
@ -22,14 +22,17 @@ SET(GA_SOURCES
make_run_ga.cpp
)
ADD_LIBRARY(ga STATIC ${GA_SOURCES})
INSTALL(TARGETS ga ARCHIVE DESTINATION ${LIB} COMPONENT libraries)
add_library(ga STATIC ${GA_SOURCES})
install(TARGETS ga ARCHIVE DESTINATION lib COMPONENT libraries)
file(GLOB HDRS *.h)
install(FILES ${HDRS} DESTINATION include/eo/ga COMPONENT headers)
######################################################################################
### 3) Optionnal
######################################################################################
SET(GA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(ga PROPERTIES VERSION "${GA_VERSION}")
set(GA_VERSION ${GLOBAL_VERSION})
set_target_properties(ga PROPERTIES VERSION "${GA_VERSION}")
######################################################################################

35
eo/src/mpi/CMakeLists.txt Normal file
View file

@ -0,0 +1,35 @@
######################################################################################
### 1) Include the sources
######################################################################################
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Define the eompi target
######################################################################################
set(EOMPI_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib)
set(LIBRARY_OUTPUT_PATH ${EOMPI_LIB_OUTPUT_PATH})
set(EOMPI_SOURCES
eoMpi.cpp
eoMpiAssignmentAlgorithm.cpp
eoMpiNode.cpp
implMpi.cpp
)
add_library(eompi STATIC ${EOMPI_SOURCES})
install(TARGETS eompi ARCHIVE DESTINATION local/${LIB} COMPONENT libraries)
file(GLOB HDRS *.h)
install(FILES ${HDRS} DESTINATION local/include${INSTALL_SUB_DIR}/eo/mpi COMPONENT headers)
######################################################################################
### 3) Optionnal
######################################################################################
set(EOMPI_VERSION ${GLOBAL_VERSION})
set_target_properties(eompi PROPERTIES VERSION "${EOMPI_VERSION}")
######################################################################################

48
eo/src/mpi/eoMpi.cpp Normal file
View file

@ -0,0 +1,48 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include "eoMpi.h"
namespace eo
{
namespace mpi
{
/**********************************************
* *********** GLOBALS ************************
* *******************************************/
eoTimerStat timerStat;
namespace Channel
{
const int Commands = 0;
const int Messages = 1;
}
namespace Message
{
const int Continue = 0;
const int Finish = 1;
const int Kill = 2;
}
const int DEFAULT_MASTER = 0;
}
}

868
eo/src/mpi/eoMpi.h Normal file
View file

@ -0,0 +1,868 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EO_MPI_H__
# define __EO_MPI_H__
# include <vector> // std::vector
# include <utils/eoLogger.h>
# include <utils/eoTimer.h>
# include <eoFunctor.h>
# include <eoExceptions.h>
# include "eoMpiNode.h"
# include "eoMpiAssignmentAlgorithm.h"
namespace eo
{
/**
* @ingroup Parallel
* @defgroup MPI Message Passing Interface
* @brief See namespace eo::mpi to have all explanations about this module.
* @{
*/
/**
* @brief MPI parallelization helpers for EO.
*
* This namespace contains parallelization functions which help to parallelize computations in EO. It is based on a
* generic algorithm, which is then customized with functors, corresponding to the algorithm main steps. These
* computations are centralized, i.e there is one central host whose role is to handle the steps of the algorithm ;
* we call it the "master". The other hosts just have to perform a "dummy" computation, which may be any kind of
* processing ; we call them, the "slaves", or less pejoratively, the "workers". Workers can communicate to each
* other, but they receive their orders from the Master and send him back some results. A worker can also be the
* master of a different parallelization process, as soon as it is a part of its work. Machines of the network, also
* called hosts, are identified by an unique number: their rank. At any time during the execution of the program,
* all the hosts know the total number of hosts.
*
* A parallelized Job is a set of tasks which are independant (i.e can be executed in random order without
* modifiying the result) and take a data input and compute a data output to be sent to the Master. The data can be
* of any type, however they have to be serialized to be sent over a network. It is sufficient that they can be
* serialized through boost.
*
* @todo For serialization purposes, don't depend upon boost. It would be easy to use only eoserial and send strings
* via mpi.
*
* The main steps of the algorithm are the following:
* - For the master:
* - Have we done with the treatment we are doing ?
* - If this is the case, we can quit.
* - Otherwise, send an input data to some available worker.
* - If there's no available worker, wait for a worker to be free.
* - When receiving the response, handle it (eventually compute something on the output data, store it...).
* - Go back to the first step.
* - For the worker, it is even easier:
* - Wait for an order.
* - If there's nothing to do, just quit.
* - Otherwise, eventually retrieve data and do the work.
* - Go back to the first step.
*
* There is of course some network adjustements to do and precisions to give there, but the main ideas are present. As the
* job is fully centralized, this is the master who tells the workers when to quit and when to work.
*
* The idea behind these MPI helpers is to be the most generic possible. If we look back at the steps of the
* algorithm, we found that the steps can be splitted into 2 parts: the first consists in the steps of any
* parallelization algorithm and the other consists in the specific parts of the algorithm. Ideally, the user should
* just have to implement the specific parts of the algorithm. We identified these parts to be:
* - For the master:
* - What does mean to have terminated ? There are only two alternatives, in our binary world: either it is
* terminated, or it is not. Hence we only need a function returning a boolean to know if we're done with the
* computation : we'll call it IsFinished.
* - What do we have to do when we send a task ? We don't have any a priori on the form of the sent data, or
* the number of sent data. Moreover, as the tasks are all independant, we don't care of who will do the
* computation, as soon as it's done. Knowing the rank of the worker will be sufficient to send him data. We
* have identified another function, taking a single argument which is the rank of the worker: we'll call it
* SendTask.
* - What do we have to do when we receive a response from a worker ? One more time, we don't know which form
* or structure can have the receive data, only the user can know. Also we let the user the charge to retrieve
* the data ; he just has to know from who the master will retrieve the data. Here is another function, taking
* a rank (the sender's one) as a function argument : this will be HandleResponse.
* - For the worker:
* - What is the processing ? It can have any nature. We just need to be sure that a data is sent back to the
* master, but it seems difficult to check that: it will be the role of the user to assert that data is sent by
* the worker at the end of an execution. We've got identified our last function: ProcessTask.
*
* In term of implementation, it would be annoying to have only abstract classes with these 4 methods to implement. It
* would mean that if you want to alter just one of these 4 functions, you have to implement a new sub class, with a
* new constructor which could have the same signature. Besides, this fashion doesn't allow you to add dynamic
* functionalities, using the design pattern Decorator for instance, without implement a class for each type of
* decoration you want to add. For these reasons, we decided to transform function into functors ; the user can then
* wrap the existing, basic comportments into more sophisticated computations, whenever he wants, and without the
* notion of order. We retrieve here the power of extension given by the design pattern Decorator.
*
* Our 4 functors could have a big amount of data in common (see eoParallelApply to have an idea).
* So as to make it easy for the user to implement these 4 functors, we consider that these functors
* have to share a common data structure. This data structure is referenced (as a pointer) in the 4 functors, so the
* user doesn't need to pass a lot of parameters to each functor constructor.
*
* There are two kinds of jobs:
* - The job which are launched a fixed and well known amount of times, i.e both master and workers know how many
* times they will be launched. They are "one shot jobs".
* - The job which are launched an unknown amount of times, for instance embedded in a while loop for which we don't
* know the amount of repetitions (typically, eoEasyEA loop is a good example, as we don't know the continuator
* condition). They are called "multi job".
* As the master tells the workers to quit, we have to differentiate these two kinds of jobs. When the job is of the
* kind "multi job", the workers would have to perform a while(true) loop so as to receive the orders ; but even if
* the master tells them to quit, they would begin another job and wait for another order, while the master would
* have quit: this would cause a deadlock and workers processes would be blocked, waiting for an order.
*/
namespace mpi
{
/**
* @brief A timer which allows user to generate statistics about computation times.
*/
extern eoTimerStat timerStat;
/**
* @brief Tags used in MPI messages for framework communication
*
* These tags are used for framework communication and fits "channels", so as to differentiate when we're
* sending an order to a worker (Commands) or data (Messages). They are not reserved by the framework and can be
* used by the user, but he is not bound to.
*
* @ingroup MPI
*/
namespace Channel
{
extern const int Commands;
extern const int Messages;
}
/**
* @brief Simple orders used by the framework.
*
* These orders are sent by the master to the workers, to indicate to them if they should receive another task
* to do (Continue), if an one shot job is done (Finish) or if a multi job is done (Kill).
*
* @ingroup MPI
*/
namespace Message
{
extern const int Continue;
extern const int Finish;
extern const int Kill;
}
/**
* @brief If the job only has one master, the user can use this constant, so as not to worry with integer ids.
*
* @ingroup MPI
*/
extern const int DEFAULT_MASTER;
/**
* @brief Base class for the 4 algorithm functors.
*
* This class can embed a data (JobData) and a wrapper, so as to make all the 4 functors wrappable.
* We can add a wrapper at initialization or at any time when executing the program.
*
* According to RAII, the boolean needDelete helps to know if we have to use the operator delete on the wrapper
* or not. Hence, if any functor is wrapped, user has just to put this boolean to true, to indicate to wrapper
* that it should call delete. This allows to mix wrapper initialized in the heap (with new) or in the stack.
*
* @param JobData a Data type, which can have any form. It can a struct, a single int, anything.
*
* @param Wrapped the type of the functor, which will be stored as a pointer under the name _wrapped.
* This allows to wrap directly the functor in functors of the same type
* here, instead of dealing with SharedDataFunction* that we would have to cast all the time.
* Doing also allows to handle the wrapped functor as the functor we're writing, when coding the wrappers,
* instead of doing some static_cast. For instance, if there are 2 functors subclasses, fA and fB, fA
* implementing doFa() and fB implementing doFb(), we could have the following code:
* @code
* struct fA_wrapper
* {
* // some code
* void doFa()
* {
* _wrapped->doFa();
* std::cout << "I'm a fA wrapper!" << std::endl;
* // if we didn't have the second template parameter, but a SharedDataFunction, we would have to do this:
* static_cast<fA*>(_wrapped)->doFa();
* // do other things (it's a wrapper)
* }
* };
*
* struct fB_wrapper
* {
* // some code
* void doFb()
* {
* _wrapped->doFb(); // and not: static_cast<fB*>(_wrapped)->doFb();
* }
* };
* @endcode
* This makes the code easier to write for the user.
*
* @ingroup MPI
*/
template< typename JobData, typename Wrapped >
struct SharedDataFunction
{
/**
* @brief Default constructor.
*
* The user is not bound to give a wrapped functor.
*/
SharedDataFunction( Wrapped * w = 0 ) : _data( 0 ), _wrapped( w ), _needDelete( false )
{
// empty
}
/**
* @brief Destructor.
*
* Calls delete on the wrapped function, only if necessary.
*/
virtual ~SharedDataFunction()
{
if( _wrapped && _wrapped->needDelete() )
{
delete _wrapped;
}
}
/**
* @brief Setter for the wrapped function.
*
* It doesn't do anything on the current wrapped function, like deleting it.
*/
void wrapped( Wrapped * w )
{
_wrapped = w;
}
/**
* @brief Setter for the data present in the functor.
*
* Calls the setter on the functor and on the wrapped functors, in a Composite pattern fashion.
*/
void data( JobData* d )
{
_data = d;
if( _wrapped )
{
_wrapped->data( d );
}
}
/**
* @brief Returns true if we need to use operator delete on this wrapper, false otherwise.
*
* Allows the user to reject delete responsability to the framework, by setting this value to true.
**/
bool needDelete() { return _needDelete; }
void needDelete( bool b ) { _needDelete = b; }
protected:
JobData* _data;
Wrapped* _wrapped; // Pointer and not a reference so as to be set at any time and to avoid affectation
bool _needDelete;
};
/**
* @brief Functor (master side) used to send a task to the worker.
*
* The user doesn't have to know which worker will receive a task, so we just indicate to master the rank of the
* worker. The data used for computation have to be explicitly sent by the master to the worker, with indicated
* rank. Once this functor has been called, the worker is considered busy until it sends a return message to the
* master.
*
* This is a functor implementing void operator()(int), and also a shared data function, containing wrapper on its
* own type.
*
* @ingroup MPI
*/
template< typename JobData >
struct SendTaskFunction : public eoUF<int, void>, public SharedDataFunction< JobData, SendTaskFunction<JobData> >
{
public:
SendTaskFunction( SendTaskFunction<JobData>* w = 0 ) : SharedDataFunction<JobData, SendTaskFunction<JobData> >( w )
{
// empty
}
virtual ~SendTaskFunction() {} // for inherited classes
};
/**
* @brief Functor (master side) used to indicate what to do when receiving a response.
*
* The master calls this function as soon as it receives some data, in some channel. Thanks to MPI, we retrieve
* the rank of the data's sender. This functor is then called with this rank. There is no memoization of a link
* between sent data and rank, so the user has to implement it, if he needs it.
*
* This is a functor implementing void operator()(int), and also a shared data function, containing wrapper on
* its own type.
*
* The master has to receive worker's data on channel (= MPI tag) eo::mpi::Channel::Messages. No other tags are
* allowed.
*
* @ingroup MPI
*/
template< typename JobData >
struct HandleResponseFunction : public eoUF<int, void>, public SharedDataFunction< JobData, HandleResponseFunction<JobData> >
{
public:
HandleResponseFunction( HandleResponseFunction<JobData>* w = 0 ) : SharedDataFunction<JobData, HandleResponseFunction<JobData> >( w )
{
// empty
}
virtual ~HandleResponseFunction() {} // for inherited classes
};
/**
* @brief Functor (worker side) implementing the processing to do.
*
* This is where the real computation happen.
* Whenever the master sends the command "Continue" to workers, which indicates the worker will receive a task,
* the worker calls this functor. The user has to explicitly retrieve the data, handle it and transmit it,
* processed, back to the master. Data sent back needs to be transmitted via channel (= MPI tag)
* eo::mpi::Channel::Messages, and no one else. If the worker does not send any data back to the master, the latter will
* consider the worker isn't done and a deadlock could occur.
*
* This is a functor implementing void operator()(), and also a shared data function, containing wrapper on its
* own type.
*
* @ingroup MPI
*/
template< typename JobData >
struct ProcessTaskFunction : public eoF<void>, public SharedDataFunction< JobData, ProcessTaskFunction<JobData> >
{
public:
ProcessTaskFunction( ProcessTaskFunction<JobData>* w = 0 ) : SharedDataFunction<JobData, ProcessTaskFunction<JobData> >( w )
{
// empty
}
virtual ~ProcessTaskFunction() {} // for inherited classes
};
/**
* @brief Functor (master side) indicating whether the job is done or not.
*
* The master loops on this functor to know when to stop. When this functor returns true, the master will wait
* for the last responses and properly stops the job. Whenever this functor returns false, the master will send
* tasks, until this functor returns true.
*
* This is a functor implementing bool operator()(), and also a shared function, containing wrapper on its own
* type.
*
* @ingroup MPI
*/
template< typename JobData >
struct IsFinishedFunction : public eoF<bool>, public SharedDataFunction< JobData, IsFinishedFunction<JobData> >
{
public:
IsFinishedFunction( IsFinishedFunction<JobData>* w = 0 ) : SharedDataFunction<JobData, IsFinishedFunction<JobData> >( w )
{
// empty
}
virtual ~IsFinishedFunction() {} // for inherited classes
};
/**
* @brief Contains all the required data and the functors to launch a job.
*
* Splitting the functors and data from the job in itself allows to use the same functors and data for multiples
* instances of the same job. You define your store once and can use it a lot of times during your program. If
* the store was included in the job, you'd have to give again all the functors and all the datas to each
* invokation of the job.
*
* Job store contains the 4 functors (pointers, so as to be able to wrap them ; references couldn't have
* permitted that) described above and the JobData used by all these functors. It contains
* also helpers to easily wrap the functors, getters and setters on all of them.
*
* The user has to implement data(), which is the getter for retrieving JobData. We don't have any idea of who
* owns the data, moreover it is impossible to initialize it in this generic JobStore, as we don't know its
* form. As a matter of fact, the user has to define this in the JobStore subclasses.
*
* @ingroup MPI
*/
template< typename JobData >
struct JobStore
{
/**
* @brief Default ctor with the 4 functors.
*/
JobStore(
SendTaskFunction<JobData>* stf,
HandleResponseFunction<JobData>* hrf,
ProcessTaskFunction<JobData>* ptf,
IsFinishedFunction<JobData>* iff
) :
_stf( stf ), _hrf( hrf ), _ptf( ptf ), _iff( iff )
{
// empty
}
/**
* @brief Empty ctor, useful for not forcing users to call the other constructor.
*
* When using this constructor, the user have to care about the 4 functors pointers, otherwise null pointer
* segfaults have to be expected.
*/
JobStore()
{
// empty
}
/**
* @brief Default destructor.
*
* JobStore is the highest layer which calls needDelete on its functors.
*/
~JobStore()
{
if( _stf->needDelete() ) delete _stf;
if( _hrf->needDelete() ) delete _hrf;
if( _ptf->needDelete() ) delete _ptf;
if( _iff->needDelete() ) delete _iff;
}
// Getters
SendTaskFunction<JobData> & sendTask() { return *_stf; }
HandleResponseFunction<JobData> & handleResponse() { return *_hrf; }
ProcessTaskFunction<JobData> & processTask() { return *_ptf; }
IsFinishedFunction<JobData> & isFinished() { return *_iff; }
// Setters
void sendTask( SendTaskFunction<JobData>* stf )
{
if( !stf )
return;
if( _stf && _stf->needDelete() )
{
delete _stf;
}
_stf = stf;
}
void handleResponse( HandleResponseFunction<JobData>* hrf )
{
if( !hrf )
return;
if( _hrf && _hrf->needDelete() )
{
delete _hrf;
}
_hrf = hrf;
}
void processTask( ProcessTaskFunction<JobData>* ptf )
{
if( !ptf )
return;
if( _ptf && _ptf->needDelete() )
{
delete _ptf;
}
_ptf = ptf;
}
void isFinished( IsFinishedFunction<JobData>* iff )
{
if( !iff )
return;
if( _iff && _iff->needDelete() )
{
delete _iff;
}
_iff = iff;
}
/**
* @brief Helpers for wrapping send task functor.
*/
void wrapSendTask( SendTaskFunction<JobData>* stf )
{
if( stf )
{
stf->wrapped( _stf );
_stf = stf;
}
}
/**
* @brief Helpers for wrapping handle response functor.
*/
void wrapHandleResponse( HandleResponseFunction<JobData>* hrf )
{
if( hrf )
{
hrf->wrapped( _hrf );
_hrf = hrf;
}
}
/**
* @brief Helpers for wrapping process task functor.
*/
void wrapProcessTask( ProcessTaskFunction<JobData>* ptf )
{
if( ptf )
{
ptf->wrapped( _ptf );
_ptf = ptf;
}
}
/**
* @brief Helpers for wrapping is finished functor.
*/
void wrapIsFinished( IsFinishedFunction<JobData>* iff )
{
if( iff )
{
iff->wrapped( _iff );
_iff = iff;
}
}
virtual JobData* data() = 0;
protected:
SendTaskFunction< JobData >* _stf;
HandleResponseFunction< JobData >* _hrf;
ProcessTaskFunction< JobData >* _ptf;
IsFinishedFunction< JobData >* _iff;
};
/**
* @example t-mpi-wrapper.cpp
*/
/**
* @brief Class implementing the centralized job algorithm.
*
* This class handles all the job algorithm. With its store and its assignment (scheduling) algorithm, it
* executes the general algorithm described above, adding some networking, so as to make the global process
* work. It initializes all the functors with the data, then launches the main loop, indicating to workers when
* they will have to work and when they will finish, by sending them a termination message (integer that can be
* customized). As the algorithm is centralized, it is also mandatory to indicate what is the MPI rank of the
* master process, hence the workers will know from who they should receive their commands.
*
* Any of the 3 master functors can launch exception, it will be catched and rethrown as a std::runtime_exception
* to the higher layers.
*
* @ingroup MPI
*/
template< class JobData >
class Job
{
public:
/**
* @brief Main constructor for Job.
*
* @param _algo The used assignment (scheduling) algorithm. It has to be initialized, with its maximum
* possible number of workers (some workers referenced in this algorithm shouldn't be busy). See
* AssignmentAlgorithm for more details.
*
* @param _masterRank The MPI rank of the master.
*
* @param _workerStopCondition Number of the message which will cause the workers to terminate. It could
* be one of the constants defined in eo::mpi::Commands, or any other integer. The user has to be sure
* that a message containing this integer will be sent to each worker on the Commands channel, otherwise
* deadlock will happen. Master sends Finish messages at the end of a simple job, but as a job can
* happen multiples times (multi job), workers don't have to really finish on these messages but on
* another message. This is here where you can configurate it. See also OneShotJob and MultiJob.
*
* @param store The JobStore containing functors and data for this job.
*/
Job( AssignmentAlgorithm& _algo,
int _masterRank,
int _workerStopCondition,
JobStore<JobData> & _store
) :
assignmentAlgo( _algo ),
masterRank( _masterRank ),
workerStopCondition( _workerStopCondition ),
comm( Node::comm() ),
// Functors
store( _store ),
sendTask( _store.sendTask() ),
handleResponse( _store.handleResponse() ),
processTask( _store.processTask() ),
isFinished( _store.isFinished() )
{
_isMaster = Node::comm().rank() == _masterRank;
sendTask.data( _store.data() );
handleResponse.data( _store.data() );
processTask.data( _store.data() );
isFinished.data( _store.data() );
}
protected:
/**
* @brief Finally block of the main algorithm
*
* Herb Sutter's trick for having a finally block, in a try/catch section: invoke a class at the
* beginning of the try, its destructor will be called in every cases.
*
* This implements the end of the master algorithm:
* - sends to all available workers that they are free,
* - waits for last responses, handles them and sends termination messages to last workers.
*/
struct FinallyBlock
{
FinallyBlock(
int _totalWorkers,
AssignmentAlgorithm& _algo,
Job< JobData > & _that
) :
totalWorkers( _totalWorkers ),
assignmentAlgo( _algo ),
that( _that ),
// global field
comm( Node::comm() )
{
// empty
}
~FinallyBlock()
{
eo::log << eo::debug << "[M" << comm.rank() << "] Frees all the idle." << std::endl;
// frees all the idle workers
timerStat.start("master_wait_for_idles");
std::vector<int> idles = assignmentAlgo.idles();
for(unsigned int i = 0; i < idles.size(); ++i)
{
comm.send( idles[i], Channel::Commands, Message::Finish );
}
timerStat.stop("master_wait_for_idles");
eo::log << eo::debug << "[M" << comm.rank() << "] Waits for all responses." << std::endl;
// wait for all responses
timerStat.start("master_wait_for_all_responses");
while( assignmentAlgo.availableWorkers() != totalWorkers )
{
bmpi::status status = comm.probe( bmpi::any_source, eo::mpi::Channel::Messages );
int wrkRank = status.source();
that.handleResponse( wrkRank );
comm.send( wrkRank, Channel::Commands, Message::Finish );
assignmentAlgo.confirm( wrkRank );
}
timerStat.stop("master_wait_for_all_responses");
eo::log << eo::debug << "[M" << comm.rank() << "] Leaving master task." << std::endl;
}
protected:
int totalWorkers;
AssignmentAlgorithm& assignmentAlgo;
Job< JobData > & that;
bmpi::communicator & comm;
};
/**
* @brief Master part of the job.
*
* Launches the parallelized job algorithm : while there is something to do (! IsFinished ), get a
* worker who will be the assignee ; if no worker is available, wait for a response, handle it and reask
* for an assignee. Then send the command and the task.
* Once there is no more to do (IsFinished), indicate to all available workers that they're free, wait
* for all the responses and send termination messages (see also FinallyBlock).
*/
void master( )
{
int totalWorkers = assignmentAlgo.availableWorkers();
eo::log << eo::debug << "[M" << comm.rank() << "] Have " << totalWorkers << " workers." << std::endl;
try {
FinallyBlock finally( totalWorkers, assignmentAlgo, *this );
while( ! isFinished() )
{
timerStat.start("master_wait_for_assignee");
int assignee = assignmentAlgo.get( );
while( assignee <= 0 )
{
eo::log << eo::debug << "[M" << comm.rank() << "] Waitin' for node..." << std::endl;
bmpi::status status = comm.probe( bmpi::any_source, eo::mpi::Channel::Messages );
int wrkRank = status.source();
eo::log << eo::debug << "[M" << comm.rank() << "] Node " << wrkRank << " just terminated." << std::endl;
handleResponse( wrkRank );
assignmentAlgo.confirm( wrkRank );
assignee = assignmentAlgo.get( );
}
timerStat.stop("master_wait_for_assignee");
eo::log << eo::debug << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl;
timerStat.start("master_wait_for_send");
comm.send( assignee, Channel::Commands, Message::Continue );
sendTask( assignee );
timerStat.stop("master_wait_for_send");
}
} catch( const std::exception & e )
{
std::string s = e.what();
s.append( " in eoMpi loop");
throw std::runtime_error( s );
}
}
/**
* @brief Worker part of the algorithm.
*
* The algorithm is more much simpler: wait for an order; if it's termination message, leave. Otherwise,
* prepare to work.
*/
void worker( )
{
int order;
timerStat.start("worker_wait_for_order");
comm.recv( masterRank, Channel::Commands, order );
timerStat.stop("worker_wait_for_order");
while( true )
{
eo::log << eo::debug << "[W" << comm.rank() << "] Waiting for an order..." << std::endl;
if ( order == workerStopCondition )
{
eo::log << eo::debug << "[W" << comm.rank() << "] Leaving worker task." << std::endl;
return;
} else if( order == Message::Continue )
{
eo::log << eo::debug << "[W" << comm.rank() << "] Processing task..." << std::endl;
processTask( );
}
timerStat.start("worker_wait_for_order");
comm.recv( masterRank, Channel::Commands, order );
timerStat.stop("worker_wait_for_order");
}
}
public:
/**
* @brief Launches the job algorithm, according to the role of the host (roles are deduced from the
* master rank indicated in the constructor).
*/
void run( )
{
( _isMaster ) ? master( ) : worker( );
}
/**
* @brief Returns true if the current host is the master, false otherwise.
*/
bool isMaster( )
{
return _isMaster;
}
protected:
AssignmentAlgorithm& assignmentAlgo;
int masterRank;
const int workerStopCondition;
bmpi::communicator& comm;
JobStore<JobData>& store;
SendTaskFunction<JobData> & sendTask;
HandleResponseFunction<JobData> & handleResponse;
ProcessTaskFunction<JobData> & processTask;
IsFinishedFunction<JobData> & isFinished;
bool _isMaster;
};
/**
* @brief Job that will be launched only once.
*
* As explained in eo::mpi documentation, jobs can happen either a well known amount of times or an unknown
* amount of times. This class implements the general case when the job is launched a well known amount of
* times. The job will be terminated on both sides (master and worker) once the master would have said it.
*
* It uses the message Message::Finish as the termination message.
*
* @ingroup MPI
*/
template< class JobData >
class OneShotJob : public Job< JobData >
{
public:
OneShotJob( AssignmentAlgorithm& algo,
int masterRank,
JobStore<JobData> & store )
: Job<JobData>( algo, masterRank, Message::Finish, store )
{
// empty
}
};
/**
* @brief Job that will be launched an unknown amount of times, in worker side.
*
* As explained in eo::mpi documentation, jobs can happen either a well known amount of times or an unknown
* amount of times. This class implements the general case when the job is launched an unknown amount of times, for
* instance in a while loop. The master will run many jobs (or the same job many times), but the workers will
* launch it only once.
*
* It uses the message Message::Kill as the termination message. This message can be launched with an EmptyJob,
* launched only by the master. If no Message::Kill is sent on the Channels::Commands, the worker will wait
* forever, which will cause a deadlock.
*
* @ingroup MPI
*/
template< class JobData >
class MultiJob : public Job< JobData >
{
public:
MultiJob ( AssignmentAlgorithm& algo,
int masterRank,
JobStore<JobData> & store )
: Job<JobData>( algo, masterRank, Message::Kill, store )
{
// empty
}
};
}
/**
* @}
*/
}
# endif // __EO_MPI_H__

View file

@ -0,0 +1,224 @@
# include "eoMpiAssignmentAlgorithm.h"
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include "eoMpiNode.h"
namespace eo
{
namespace mpi
{
const int REST_OF_THE_WORLD = -1;
/********************************************************
* DYNAMIC ASSIGNMENT ALGORITHM *************************
*******************************************************/
DynamicAssignmentAlgorithm::DynamicAssignmentAlgorithm( )
{
for(int i = 1; i < Node::comm().size(); ++i)
{
availableWrk.push_back( i );
}
}
DynamicAssignmentAlgorithm::DynamicAssignmentAlgorithm( int unique )
{
availableWrk.push_back( unique );
}
DynamicAssignmentAlgorithm::DynamicAssignmentAlgorithm( const std::vector<int> & workers )
{
availableWrk = workers;
}
DynamicAssignmentAlgorithm::DynamicAssignmentAlgorithm( int first, int last )
{
if( last == REST_OF_THE_WORLD )
{
last = Node::comm().size() - 1;
}
for( int i = first; i <= last; ++i)
{
availableWrk.push_back( i );
}
}
int DynamicAssignmentAlgorithm::get( )
{
int assignee = -1;
if (! availableWrk.empty() )
{
assignee = availableWrk.back();
availableWrk.pop_back();
}
return assignee;
}
int DynamicAssignmentAlgorithm::availableWorkers()
{
return availableWrk.size();
}
void DynamicAssignmentAlgorithm::confirm( int rank )
{
availableWrk.push_back( rank );
}
std::vector<int> DynamicAssignmentAlgorithm::idles( )
{
return availableWrk;
}
void DynamicAssignmentAlgorithm::reinit( int _ )
{
++_;
// nothing to do
}
/********************************************************
* STATIC ASSIGNMENT ALGORITHM **************************
*******************************************************/
StaticAssignmentAlgorithm::StaticAssignmentAlgorithm( const std::vector<int>& workers, int runs )
{
init( workers, runs );
}
StaticAssignmentAlgorithm::StaticAssignmentAlgorithm( int first, int last, int runs )
{
std::vector<int> workers;
if( last == REST_OF_THE_WORLD )
{
last = Node::comm().size() - 1;
}
for(int i = first; i <= last; ++i)
{
workers.push_back( i );
}
init( workers, runs );
}
StaticAssignmentAlgorithm::StaticAssignmentAlgorithm( int runs )
{
std::vector<int> workers;
for(int i = 1; i < Node::comm().size(); ++i)
{
workers.push_back( i );
}
init( workers, runs );
}
StaticAssignmentAlgorithm::StaticAssignmentAlgorithm( int unique, int runs )
{
std::vector<int> workers;
workers.push_back( unique );
init( workers, runs );
}
void StaticAssignmentAlgorithm::init( const std::vector<int> & workers, int runs )
{
unsigned int nbWorkers = workers.size();
freeWorkers = nbWorkers;
busy.clear();
busy.resize( nbWorkers, false );
realRank = workers;
if( runs <= 0 )
{
return;
}
attributions.clear();
attributions.reserve( nbWorkers );
// Let be the euclidean division of runs by nbWorkers :
// runs == q * nbWorkers + r, 0 <= r < nbWorkers
// This one liner affects q requests to each worker
for (unsigned int i = 0; i < nbWorkers; attributions[i++] = runs / nbWorkers) ;
// The first line computes r and the one liner affects the remaining
// r requests to workers, in ascending order
unsigned int diff = runs - (runs / nbWorkers) * nbWorkers;
for (unsigned int i = 0; i < diff; ++attributions[i++]);
}
int StaticAssignmentAlgorithm::get( )
{
int assignee = -1;
for( unsigned i = 0; i < busy.size(); ++i )
{
if( !busy[i] && attributions[i] > 0 )
{
busy[i] = true;
--freeWorkers;
assignee = realRank[ i ];
break;
}
}
return assignee;
}
int StaticAssignmentAlgorithm::availableWorkers( )
{
return freeWorkers;
}
std::vector<int> StaticAssignmentAlgorithm::idles()
{
std::vector<int> ret;
for(unsigned int i = 0; i < busy.size(); ++i)
{
if( !busy[i] )
{
ret.push_back( realRank[i] );
}
}
return ret;
}
void StaticAssignmentAlgorithm::confirm( int rank )
{
int i = -1; // i is the real index in table
for( unsigned int j = 0; j < realRank.size(); ++j )
{
if( realRank[j] == rank )
{
i = j;
break;
}
}
--attributions[ i ];
busy[ i ] = false;
++freeWorkers;
}
void StaticAssignmentAlgorithm::reinit( int runs )
{
init( realRank, runs );
}
}
}

View file

@ -0,0 +1,239 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __MPI_ASSIGNMENT_ALGORITHM_H__
# define __MPI_ASSIGNMENT_ALGORITHM_H__
# include <vector> // std::vector
namespace eo
{
namespace mpi
{
/**
* @brief Constant indicating to use all the resting available workers, in assignment algorithms constructor
* using an interval.
*
* @ingroup MPI
*/
extern const int REST_OF_THE_WORLD;
/**
* @brief Contains informations on the available workers and allows to find assignees for jobs.
*
* Available workers are workers who aren't processing anything. When they've received an order, workers switch
* from the state "available" to the state "busy", and the master has to wait for their response for considering
* them available again.
*
* @ingroup MPI
*/
struct AssignmentAlgorithm
{
/**
* @brief Gets the rank of an available worker, so as to send it a task.
*
* @return The MPI rank of an available worker, or -1 if there is no available worker.
*/
virtual int get( ) = 0;
/**
* @brief Gets the number of total available workers.
*
* Before the first call, it is equal to the total number of present workers, as specified in the
* specific assignment algorithm constructor. It allows the Job class to know when all the responses have
* been received, by comparing this number to the total number of workers.
*
* @return Integer indicating how many workers are available.
*/
virtual int availableWorkers( ) = 0;
/**
* @brief Reinject the worker of indicated rank in the available state.
*
* @param wrkRank The MPI rank of the worker who has finished its job.
*/
virtual void confirm( int wrkRank ) = 0;
/**
* @brief Indicates who are the workers which do nothing.
*
* At the end of the algorithm, the master has to warn all the workers that it's done. All the workers mean,
* the workers which are currently processing data, and the other ones who could be waiting : the idles.
* This function indicates to the master which worker aren't doing anything.
*
* @return A std::vector containing all the MPI ranks of the idles workers.
*/
virtual std::vector<int> idles( ) = 0;
/**
* @brief Reinitializes the assignment algorithm with the right number of runs.
*
* In fact, this is only useful for static assignment algorithm, which has to be reinitialized every time
* it's used, in the case of a Multi Job. It's the user's responsability to call this function.
*
* @todo Not really clean. Find a better way to do it.
*/
virtual void reinit( int runs ) = 0;
};
/**
* @brief Assignment (scheduling) algorithm which handles workers in a queue.
*
* With this assignment algorithm, workers are put in a queue and may be called an unlimited number of times.
* Whenever a worker returns, it is added to the queue, and it becomes available for the next call to get().
* The available workers are all located in the queue at any time, so the number of available workers is
* directly equal to the size of the queue.
*
* This kind of assignment is adapted for tasks whose execution time is stochastic or unknown, but without any
* warranty to be faster than other assignments.
*
* @ingroup MPI
*/
struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm
{
public:
/**
* @brief Uses all the hosts whose rank is higher to 1, inclusive, as workers.
*/
DynamicAssignmentAlgorithm( );
/**
* @brief Uses the unique host with given rank as a worker.
*
* @param unique MPI rank of the unique worker.
*/
DynamicAssignmentAlgorithm( int unique );
/**
* @brief Uses the workers whose ranks are present in the argument as workers.
*
* @param workers std::vector containing MPI ranks of workers.
*/
DynamicAssignmentAlgorithm( const std::vector<int> & workers );
/**
* @brief Uses a range of ranks as workers.
*
* @param first The first worker to be included (inclusive)
* @param last The last worker to be included (inclusive). If last == eo::mpi::REST_OF_THE_WORLD, all
* hosts whose rank is higher than first are taken.
*/
DynamicAssignmentAlgorithm( int first, int last );
virtual int get( );
int availableWorkers();
void confirm( int rank );
std::vector<int> idles( );
void reinit( int _ );
protected:
std::vector< int > availableWrk;
};
/**
* @brief Assignment algorithm which gives to each worker a precise number of tasks to do, in a round robin
* fashion.
*
* This scheduling algorithm attributes, at initialization or when calling reinit(), a fixed amount of runs to
* distribute to the workers. The amount of runs is then equally distributed between all workers ; if total
* number of runs is not a direct multiple of workers number, then remainding unaffected runs are distributed to
* workers from the first to the last, in a round-robin fashion.
*
* This scheduling should be used when the amount of runs can be computed or is fixed and when we guess that the
* duration of processing task will be the same for each run. There is no warranty that this algorithm is more
* or less efficient that another one. When having a doubt, use DynamicAssignmentAlgorithm.
*
* @ingroup MPI
*/
struct StaticAssignmentAlgorithm : public AssignmentAlgorithm
{
public:
/**
* @brief Uses a given precise set of workers.
*
* @param workers std::vector of MPI ranks of workers which will be used.
* @param runs Fixed amount of runs, strictly positive.
*/
StaticAssignmentAlgorithm( const std::vector<int>& workers, int runs );
/**
* @brief Uses a range of workers.
*
* @param first The first MPI rank of worker to use
* @param last The last MPI rank of worker to use. If it's equal to REST_OF_THE_WORLD, then all the
* workers from the first one are taken as workers.
* @param runs Fixed amount of runs, strictly positive.
*/
StaticAssignmentAlgorithm( int first, int last, int runs );
/**
* @brief Uses all the hosts whose rank is higher than 1 (inclusive) as workers.
*
* @param runs Fixed amount of runs, strictly positive. If it's not set, you'll have to call reinit()
* later.
*/
StaticAssignmentAlgorithm( int runs = 0 );
/**
* @brief Uses an unique host as worker.
*
* @param unique The MPI rank of the host which will be the worker.
* @param runs Fixed amount of runs, strictly positive.
*/
StaticAssignmentAlgorithm( int unique, int runs );
private:
/**
* @brief Initializes the static scheduling.
*
* Gives to each worker an equal attribution number, equal to runs / workers.size(), eventually plus one
* if number of workers is not a divisor of runs.
*
* @param workers Vector of hosts' ranks
* @param runs Fixed amount of runs, strictly positive.
*/
void init( const std::vector<int> & workers, int runs );
public:
int get( );
int availableWorkers( );
std::vector<int> idles();
void confirm( int rank );
void reinit( int runs );
private:
std::vector<int> attributions;
std::vector<int> realRank;
std::vector<bool> busy;
unsigned int freeWorkers;
};
}
}
# endif // __MPI_ASSIGNMENT_ALGORITHM_H__

40
eo/src/mpi/eoMpiNode.cpp Normal file
View file

@ -0,0 +1,40 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include "eoMpiNode.h"
namespace eo
{
namespace mpi
{
void Node::init( int argc, char** argv )
{
static bmpi::environment env( argc, argv );
}
bmpi::communicator& Node::comm()
{
return _comm;
}
bmpi::communicator Node::_comm;
}
}

65
eo/src/mpi/eoMpiNode.h Normal file
View file

@ -0,0 +1,65 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __MPI_NODE_H__
# define __MPI_NODE_H__
# include "implMpi.h"
namespace bmpi = mpi;
namespace eo
{
namespace mpi
{
/**
* @brief Global object used to reach mpi::communicator everywhere.
*
* mpi::communicator is the main object used to send and receive messages between the different hosts of
* a MPI algorithm.
*
* @ingroup MPI
*/
class Node
{
public:
/**
* @brief Initializes the MPI environment with argc and argv.
*
* Should be called at the beginning of every parallel program.
*
* @param argc Main's argc
* @param argv Main's argv
*/
static void init( int argc, char** argv );
/**
* @brief Returns the global mpi::communicator
*/
static bmpi::communicator& comm();
protected:
static bmpi::communicator _comm;
};
}
}
# endif // __MPI_NODE_H__

515
eo/src/mpi/eoMultiStart.h Normal file
View file

@ -0,0 +1,515 @@
# ifndef __EO_MULTISTART_H__
# define __EO_MULTISTART_H__
# include <eo>
# include "eoMpi.h"
/**
* @ingroup MPI
* @{
*/
/**
* @file eoMultiStart.h
*
* Contains implementation of a MPI job which consists in a multi start, which basically consists in the following:
* the same eoAlgo is launched on computers of a clusters, with different seeds for each. As the eoAlgo are most of
* the time stochastics, the results won't be the same. It is fully equivalent to launch the same program but with
* different seeds.
*
* It follows the structure of a MPI job, as described in eoMpi.h. The basic algorithm is trivial:
* - Loop while we have a run to perform.
* - Worker performs runs and send their best solution (individual with best fitness) to the master.
* - Master retrieves the best solution and adds it to a eoPop of best solutions (the user can chooses what he does
* with this population, for instance: retrieve the best element, etc.)
*
* The principal concerns about this algorithm are:
* - How do we reinitialize the algorithm? An eoAlgo can have several forms, and initializations have to be performed
* before each "start". We can hence decide whether we reinits the population or keep the same population obtained
* after the previous start, we have to reinitialize continuator, etc. This is customizable in the store.
*
* - Which seeds should be chosen? If we want the run to be re-runnable with the same results, we need to be sure that
* the seeds are the same. But user can not care about this, and just want random seeds. This is customizable in the
* store.
*
* These concerns are handled by functors, inheriting from MultiStartStore<EOT>::ResetAlgo (for the first concern), and
* MultiStartStore<EOT>::GetSeeds (for the second one). There are default implementations, but there is no problem about
* specializing them or coding your own, by directly inheriting from them.
*
* @ingroup MPI
*/
namespace eo
{
namespace mpi
{
/**
* @brief Data used by the Multi Start job.
*
* This data is shared between the different Job functors. More details are given for each attribute.
*/
template< class EOT >
struct MultiStartData
{
typedef eoUF< eoPop<EOT>&, void> ResetAlgo;
MultiStartData(
bmpi::communicator& _comm,
eoAlgo<EOT>& _algo,
int _masterRank,
ResetAlgo & _resetAlgo )
:
runs( 0 ), bests(), pop(),
comm( _comm ), algo( _algo ), resetAlgo( _resetAlgo ), masterRank( _masterRank )
{
// empty
}
// dynamic parameters
/**
* @brief Total remaining number of runs.
*
* It's decremented as the runs are performed.
*/
int runs;
/**
* @brief eoPop of the best individuals, which are the one sent by the workers.
*/
eoPop< EOT > bests;
/**
* @brief eoPop on which the worker is working.
*/
eoPop< EOT > pop;
// static parameters
/**
* @brief Communicator, used to send and retrieve messages.
*/
bmpi::communicator& comm;
/**
* @brief Algorithm which will be performed by the worker.
*/
eoAlgo<EOT>& algo;
/**
* @brief Reset Algo functor, which defines how to reset the algo (above) before re running it.
*/
ResetAlgo& resetAlgo;
// Rank of master
int masterRank;
};
/**
* @brief Send task (master side) in the Multi Start job.
*
* It only consists in decrementing the number of runs, as the worker already have the population and
* all the necessary parameters to run the eoAlgo.
*/
template< class EOT >
class SendTaskMultiStart : public SendTaskFunction< MultiStartData< EOT > >
{
public:
using SendTaskFunction< MultiStartData< EOT > >::_data;
void operator()( int wrkRank )
{
wrkRank++; // unused
--(_data->runs);
}
};
/**
* @brief Handle Response (master side) in the Multi Start job.
*
* It consists in retrieving the best solution sent by the worker and adds it to a population of best
* solutions.
*/
template< class EOT >
class HandleResponseMultiStart : public HandleResponseFunction< MultiStartData< EOT > >
{
public:
using HandleResponseFunction< MultiStartData< EOT > >::_data;
void operator()( int wrkRank )
{
EOT individual;
MultiStartData< EOT >& d = *_data;
d.comm.recv( wrkRank, eo::mpi::Channel::Messages, individual );
d.bests.push_back( individual );
}
};
/**
* @brief Process Task (worker side) in the Multi Start job.
*
* Consists in resetting the algorithm and launching it on the population, then
* send the best individual (the one with the best fitness) to the master.
*/
template< class EOT >
class ProcessTaskMultiStart : public ProcessTaskFunction< MultiStartData< EOT > >
{
public:
using ProcessTaskFunction< MultiStartData<EOT > >::_data;
void operator()()
{
_data->resetAlgo( _data->pop );
_data->algo( _data->pop );
_data->comm.send( _data->masterRank, eo::mpi::Channel::Messages, _data->pop.best_element() );
}
};
/**
* @brief Is Finished (master side) in the Multi Start job.
*
* The job is finished if and only if all the runs have been performed.
*/
template< class EOT >
class IsFinishedMultiStart : public IsFinishedFunction< MultiStartData< EOT > >
{
public:
using IsFinishedFunction< MultiStartData< EOT > >::_data;
bool operator()()
{
return _data->runs <= 0;
}
};
/**
* @brief Store for the Multi Start job.
*
* Contains the data used by the workers (algo,...) and functor to
* send the seeds.
*/
template< class EOT >
class MultiStartStore : public JobStore< MultiStartData< EOT > >
{
public:
/**
* @brief Generic functor to reset an algorithm before it's launched by
* the worker.
*
* This reset algorithm should reinits population (if necessary), continuator, etc.
*/
typedef typename MultiStartData<EOT>::ResetAlgo ResetAlgo;
/**
* @brief Generic functor which returns a vector of seeds for the workers.
*
* If this vector hasn't enough seeds to send, random ones are generated and
* sent to the workers.
*/
typedef eoUF< int, std::vector<int> > GetSeeds;
/**
* @brief Default ctor for MultiStartStore.
*
* @param algo The algorithm to launch in parallel
* @param masterRank The MPI rank of the master
* @param resetAlgo The ResetAlgo functor
* @param getSeeds The GetSeeds functor
*/
MultiStartStore(
eoAlgo<EOT> & algo,
int masterRank,
ResetAlgo & resetAlgo,
GetSeeds & getSeeds
)
: _data( eo::mpi::Node::comm(), algo, masterRank, resetAlgo ),
_getSeeds( getSeeds ),
_masterRank( masterRank )
{
// Default job functors for this one.
this->_iff = new IsFinishedMultiStart< EOT >;
this->_iff->needDelete(true);
this->_stf = new SendTaskMultiStart< EOT >;
this->_stf->needDelete(true);
this->_hrf = new HandleResponseMultiStart< EOT >;
this->_hrf->needDelete(true);
this->_ptf = new ProcessTaskMultiStart< EOT >;
this->_ptf->needDelete(true);
}
/**
* @brief Send new seeds to the workers before a job.
*
* Uses the GetSeeds functor given in constructor. If there's not
* enough seeds to send, random seeds are sent to the workers.
*
* @param workers Vector of MPI ranks of the workers
* @param runs The number of runs to perform
*/
void init( const std::vector<int>& workers, int runs )
{
_data.runs = runs;
unsigned nbWorkers = workers.size();
std::vector< int > seeds = _getSeeds( nbWorkers );
if( eo::mpi::Node::comm().rank() == _masterRank )
{
if( seeds.size() < nbWorkers )
{
// Random seeds
for( unsigned i = seeds.size(); i < nbWorkers; ++i )
{
seeds.push_back( eo::rng.rand() );
}
}
for( unsigned i = 0 ; i < nbWorkers ; ++i )
{
int wrkRank = workers[i];
eo::mpi::Node::comm().send( wrkRank, eo::mpi::Channel::Commands, seeds[ i ] );
}
} else
{
int seed;
eo::mpi::Node::comm().recv( _masterRank, eo::mpi::Channel::Commands, seed );
eo::log << eo::debug << eo::mpi::Node::comm().rank() << "- Seed: " << seed << std::endl;
eo::rng.reseed( seed );
}
}
MultiStartData<EOT>* data()
{
return &_data;
}
private:
MultiStartData< EOT > _data;
GetSeeds & _getSeeds;
int _masterRank;
};
/**
* @brief MultiStart job, created for convenience.
*
* This is an OneShotJob, which means workers leave it along with
* the master.
*/
template< class EOT >
class MultiStart : public OneShotJob< MultiStartData< EOT > >
{
public:
MultiStart( AssignmentAlgorithm & algo,
int masterRank,
MultiStartStore< EOT > & store,
// dynamic parameters
int runs ) :
OneShotJob< MultiStartData< EOT > >( algo, masterRank, store )
{
store.init( algo.idles(), runs );
}
/**
* @brief Returns the best solution, at the end of the job.
*
* Warning: if you call this function from a worker, or from the master before the
* launch of the job, you will only get an empty population!
*
* @return Population of best individuals retrieved by the master.
*/
eoPop<EOT>& best_individuals()
{
return this->store.data()->bests;
}
};
/*************************************
* DEFAULT GET SEEDS IMPLEMENTATIONS *
************************************/
/**
* @brief Uses the internal default seed generator to get seeds,
* which means: random seeds are sent.
*/
template<class EOT>
struct DummyGetSeeds : public MultiStartStore<EOT>::GetSeeds
{
std::vector<int> operator()( int n )
{
return std::vector<int>();
}
};
/**
* @brief Sends seeds to the workers, which are multiple of a number
* given by the master. If no number is given, a random one is used.
*
* This functor ensures that even if the same store is used with
* different jobs, the seeds will be different.
*/
template<class EOT>
struct MultiplesOfNumber : public MultiStartStore<EOT>::GetSeeds
{
MultiplesOfNumber ( int n = 0 )
{
while( n == 0 )
{
n = eo::rng.rand();
}
_seed = n;
_i = 0;
}
std::vector<int> operator()( int n )
{
std::vector<int> ret;
for( unsigned int i = 0; i < n; ++i )
{
ret.push_back( (++_i) * _seed );
}
return ret;
}
private:
unsigned int _seed;
unsigned int _i;
};
/**
* @brief Returns random seeds to the workers. We can controle which seeds are generated
* by precising the seed of the master.
*/
template<class EOT>
struct GetRandomSeeds : public MultiStartStore<EOT>::GetSeeds
{
GetRandomSeeds( int seed )
{
eo::rng.reseed( seed );
}
std::vector<int> operator()( int n )
{
std::vector<int> ret;
for(int i = 0; i < n; ++i)
{
ret.push_back( eo::rng.rand() );
}
return ret;
}
};
/**************************************
* DEFAULT RESET ALGO IMPLEMENTATIONS *
**************************************/
/**
* @brief For a Genetic Algorithm, reinits the population by copying the original one
* given in constructor, and reinits the continuator.
*
* The evaluator should also be given, as the population needs to be evaluated
* before each run.
*/
template<class EOT>
struct ReuseOriginalPopEA: public MultiStartStore<EOT>::ResetAlgo
{
ReuseOriginalPopEA(
eoCountContinue<EOT> & continuator,
const eoPop<EOT>& originalPop,
eoEvalFunc<EOT>& eval) :
_continuator( continuator ),
_originalPop( originalPop ),
_pop_eval( eval )
{
// empty
}
ReuseOriginalPopEA(
eoCountContinue<EOT> & continuator,
const eoPop<EOT>& originalPop,
eoPopEvalFunc<EOT>& pop_eval
) :
_continuator( continuator ),
_originalPop( originalPop ),
_pop_eval( pop_eval )
{
// empty
}
void operator()( eoPop<EOT>& pop )
{
pop = _originalPop; // copies the original population
_pop_eval( pop, pop );
_continuator.reset();
}
private:
eoCountContinue<EOT> & _continuator;
const eoPop<EOT>& _originalPop;
eoPopEvalFunc<EOT>& _pop_eval;
};
/**
* @brief For a Genetic Algorithm, reuses the same population without
* modifying it after a run.
*
* This means, if you launch a run after another one, you'll make evolve
* the same population.
*
* The evaluator should also be sent, as the population needs to be evaluated
* at the first time.
*/
template< class EOT >
struct ReuseSamePopEA : public MultiStartStore<EOT>::ResetAlgo
{
ReuseSamePopEA(
eoCountContinue<EOT>& continuator,
const eoPop<EOT>& originalPop,
eoEvalFunc<EOT>& eval
) :
_continuator( continuator ),
_originalPop( originalPop ),
_firstTime( true )
{
for( unsigned i = 0, size = originalPop.size();
i < size; ++i )
{
eval(_originalPop[i]);
}
}
ReuseSamePopEA(
eoCountContinue<EOT>& continuator,
const eoPop<EOT>& originalPop,
eoPopEvalFunc<EOT>& pop_eval
) :
_continuator( continuator ),
_originalPop( originalPop ),
_firstTime( true )
{
pop_eval( _originalPop, _originalPop );
}
void operator()( eoPop<EOT>& pop )
{
if( _firstTime )
{
pop = _originalPop;
_firstTime = false;
}
_continuator.reset();
}
protected:
eoCountContinue<EOT>& _continuator;
eoPop<EOT> _originalPop;
bool _firstTime;
};
} // namespace mpi
} // namespace eo
/**
* @}
*/
# endif // __EO_MULTISTART_H__

View file

@ -0,0 +1,387 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EO_PARALLEL_APPLY_H__
# define __EO_PARALLEL_APPLY_H__
# include "eoMpi.h"
# include <eoFunctor.h> // eoUF
# include <vector> // std::vector population
/**
* @file eoParallelApply.h
*
* @brief Applies a functor with single parameter to elements of a table, in a parallel fashion.
*
* This file contains all the required classes to do a parallel apply of a table, in a parallel fashion. This can be
* very useful when applying the function can be made without any dependances within the data. In EO, it occurs in
* particular during the evaluation: the number of individuals to evaluate can be really high, and the evaluation of one
* individual is independant from the evaluation of other individuals.
*
* Elements in the table are directly replaced, as the table is given by reference. No new table is made during the
* process.
*
* User can tune this job, indicating how many elements of the table should be sent and evaluated by a worker, at a
* time: this is called the "packet size", as individuals are groupped into a packet of individuals which are sent to
* the worker before evaluation. The problem of choosing the optimal packet size is beyond the purposes of this documentation
* and deserves a theoritical study.
*
* This job is the parallel equivalent to the function apply<EOT>, defined in apply.h. It just applies the function to
* every element of a table. In Python or Javascript, it's the equivalent of the function Map.
*/
namespace eo
{
namespace mpi
{
/**
* @brief Structure used to save assignment to a worker, i.e which slice of the table it has to process.
*
* This slice is defined by the index of the first evaluated argument and the number of processed elements.
*/
struct ParallelApplyAssignment
{
int index;
int size;
};
/**
* @brief Data useful for a parallel apply (map).
*
* A parallel apply needs at least the functor to apply to every element of the table, and the table itself,
* whereas it can be set later with the function init(). Master rank is also needed, to send it informations and
* receive informations from it, inside the functors (the job knows these values, but the functors don't). The
* size of a packet can be tuned here.
*
* Internal attributes contain:
* - (useful for master) the index of the next element to be evaluated.
* - (useful for master) a map containing links between MPI ranks and slices of the table which the worker with
* this rank has evaluated. Without this map, when receiving results from a worker, the master couldn't be
* able to replace the right elements in the table.
*
* @ingroup MPI
*/
template<class EOT>
struct ParallelApplyData
{
/**
* @brief Ctor for Parallel apply (map) data.
*
* @param _proc The functor to apply on each element in the table
* @param _masterRank The MPI rank of the master
* @param _packetSize The number of elements on which the function will be applied by the worker, at a time.
* @param table The table to apply. If this value is NULL, user will have to call init() before launching the
* job.
*/
ParallelApplyData(
eoUF<EOT&, void> & _proc,
int _masterRank,
int _packetSize,
std::vector<EOT> * table = 0
) :
_table( table ), func( _proc ), index( 0 ), packetSize( _packetSize ), masterRank( _masterRank ), comm( Node::comm() )
{
if ( _packetSize <= 0 )
{
throw std::runtime_error("Packet size should not be negative.");
}
if( table )
{
size = table->size();
}
}
/**
* @brief Reinitializes the data for a new table to evaluate.
*/
void init( std::vector<EOT>& table )
{
index = 0;
size = table.size();
_table = &table;
assignedTasks.clear();
}
std::vector<EOT>& table()
{
return *_table;
}
// All elements are public since functors will often use them.
std::vector<EOT> * _table;
eoUF<EOT&, void> & func;
int index;
int size;
std::map< int /* worker rank */, ParallelApplyAssignment /* last assignment */> assignedTasks;
int packetSize;
std::vector<EOT> tempArray;
int masterRank;
bmpi::communicator& comm;
};
/**
* @brief Send task functor implementation for the parallel apply (map) job.
*
* Master side: Sends a slice of the table to evaluate to the worker.
*
* Implementation details:
* Finds the next slice of data to send to the worker, sends first the size and then the data, and memorizes
* that this slice has been distributed to the worker, then updates the next position of element to evaluate.
*/
template< class EOT >
class SendTaskParallelApply : public SendTaskFunction< ParallelApplyData<EOT> >
{
public:
using SendTaskFunction< ParallelApplyData<EOT> >::_data;
SendTaskParallelApply( SendTaskParallelApply<EOT> * w = 0 ) : SendTaskFunction< ParallelApplyData<EOT> >( w )
{
// empty
}
void operator()(int wrkRank)
{
int futureIndex;
if( _data->index + _data->packetSize < _data->size )
{
futureIndex = _data->index + _data->packetSize;
} else {
futureIndex = _data->size;
}
int sentSize = futureIndex - _data->index ;
_data->comm.send( wrkRank, eo::mpi::Channel::Messages, sentSize );
eo::log << eo::debug << "Evaluating individual " << _data->index << std::endl;
_data->assignedTasks[ wrkRank ].index = _data->index;
_data->assignedTasks[ wrkRank ].size = sentSize;
_data->comm.send( wrkRank, eo::mpi::Channel::Messages, & ( (_data->table())[ _data->index ] ) , sentSize );
_data->index = futureIndex;
}
};
/**
* @brief Handle response functor implementation for the parallel apply (map) job.
*
* Master side: Replaces the slice of data attributed to the worker in the table.
*/
template< class EOT >
class HandleResponseParallelApply : public HandleResponseFunction< ParallelApplyData<EOT> >
{
public:
using HandleResponseFunction< ParallelApplyData<EOT> >::_data;
HandleResponseParallelApply( HandleResponseParallelApply<EOT> * w = 0 ) : HandleResponseFunction< ParallelApplyData<EOT> >( w )
{
// empty
}
void operator()(int wrkRank)
{
_data->comm.recv( wrkRank, eo::mpi::Channel::Messages, & (_data->table()[ _data->assignedTasks[wrkRank].index ] ), _data->assignedTasks[wrkRank].size );
}
};
/**
* @brief Process task functor implementation for the parallel apply (map) job.
*
* Worker side: apply the function to the given slice of data.
*
* Implementation details: retrieves the number of elements to evaluate, retrieves them, applies the function
* and then returns the results.
*/
template< class EOT >
class ProcessTaskParallelApply : public ProcessTaskFunction< ParallelApplyData<EOT> >
{
public:
using ProcessTaskFunction< ParallelApplyData<EOT> >::_data;
ProcessTaskParallelApply( ProcessTaskParallelApply<EOT> * w = 0 ) : ProcessTaskFunction< ParallelApplyData<EOT> >( w )
{
// empty
}
void operator()()
{
int recvSize;
_data->comm.recv( _data->masterRank, eo::mpi::Channel::Messages, recvSize );
_data->tempArray.resize( recvSize );
_data->comm.recv( _data->masterRank, eo::mpi::Channel::Messages, & _data->tempArray[0] , recvSize );
timerStat.start("worker_processes");
for( int i = 0; i < recvSize ; ++i )
{
_data->func( _data->tempArray[ i ] );
}
timerStat.stop("worker_processes");
_data->comm.send( _data->masterRank, eo::mpi::Channel::Messages, & _data->tempArray[0], recvSize );
}
};
/**
* @brief Is finished functor implementation for the parallel apply (map) job.
*
* Master side: returns true if and only if the whole table has been evaluated. The job is also terminated only
* when the whole table has been evaluated.
*/
template< class EOT >
class IsFinishedParallelApply : public IsFinishedFunction< ParallelApplyData<EOT> >
{
public:
using IsFinishedFunction< ParallelApplyData<EOT> >::_data;
IsFinishedParallelApply( IsFinishedParallelApply<EOT> * w = 0 ) : IsFinishedFunction< ParallelApplyData<EOT> >( w )
{
// empty
}
bool operator()()
{
return _data->index == _data->size;
}
};
/**
* @brief Store containing all the datas and the functors for the parallel apply (map) job.
*
* User can tune functors when constructing the object. For each functor which is not given, a default one is
* generated.
*
* @ingroup MPI
*/
template< class EOT >
struct ParallelApplyStore : public JobStore< ParallelApplyData<EOT> >
{
using JobStore< ParallelApplyData<EOT> >::_stf;
using JobStore< ParallelApplyData<EOT> >::_hrf;
using JobStore< ParallelApplyData<EOT> >::_ptf;
using JobStore< ParallelApplyData<EOT> >::_iff;
/**
* @brief Main constructor for the parallel apply (map) job.
*
* @param _proc The procedure to apply to each element of the table.
* @param _masterRank The rank of the master process.
* @param _packetSize The number of elements of the table to be evaluated at a time, by the worker.
* @param stpa Pointer to Send Task parallel apply functor descendant. If null, a default one is used.
* @param hrpa Pointer to Handle Response parallel apply functor descendant. If null, a default one is used.
* @param ptpa Pointer to Process Task parallel apply functor descendant. If null, a default one is used.
* @param ifpa Pointer to Is Finished parallel apply functor descendant. If null, a default one is used.
*/
ParallelApplyStore(
eoUF<EOT&, void> & _proc,
int _masterRank,
int _packetSize = 1,
// JobStore functors
SendTaskParallelApply<EOT> * stpa = 0,
HandleResponseParallelApply<EOT>* hrpa = 0,
ProcessTaskParallelApply<EOT>* ptpa = 0,
IsFinishedParallelApply<EOT>* ifpa = 0
) :
_data( _proc, _masterRank, _packetSize )
{
if( stpa == 0 ) {
stpa = new SendTaskParallelApply<EOT>;
stpa->needDelete( true );
}
if( hrpa == 0 ) {
hrpa = new HandleResponseParallelApply<EOT>;
hrpa->needDelete( true );
}
if( ptpa == 0 ) {
ptpa = new ProcessTaskParallelApply<EOT>;
ptpa->needDelete( true );
}
if( ifpa == 0 ) {
ifpa = new IsFinishedParallelApply<EOT>;
ifpa->needDelete( true );
}
_stf = stpa;
_hrf = hrpa;
_ptf = ptpa;
_iff = ifpa;
}
ParallelApplyData<EOT>* data() { return &_data; }
/**
* @brief Reinits the store with a new table to evaluate.
*
* @param _pop The table of elements to be evaluated.
*/
void data( std::vector<EOT>& _pop )
{
_data.init( _pop );
}
virtual ~ParallelApplyStore() // for inheritance purposes only
{
}
protected:
ParallelApplyData<EOT> _data;
};
/**
* @brief Parallel apply job. Present for convenience only.
*
* A typedef wouldn't have been working, as typedef on templates don't work in C++. Traits would be a
* disgraceful overload for the user.
*
* @ingroup MPI
* @see eoParallelApply.h
*/
template< typename EOT >
class ParallelApply : public MultiJob< ParallelApplyData<EOT> >
{
public:
ParallelApply(
AssignmentAlgorithm & algo,
int _masterRank,
ParallelApplyStore<EOT> & store
) :
MultiJob< ParallelApplyData<EOT> >( algo, _masterRank, store )
{
// empty
}
};
/**
* @example t-mpi-parallelApply.cpp
* @example t-mpi-multipleRoles.cpp
*/
}
}
# endif // __EO_PARALLEL_APPLY_H__

140
eo/src/mpi/eoTerminateJob.h Normal file
View file

@ -0,0 +1,140 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EO_TERMINATE_H__
# define __EO_TERMINATE_H__
# include "eoMpi.h"
namespace eo
{
namespace mpi
{
/**
* @ingroup MPI
* @{
*/
/**
* @brief Send task functor which does nothing.
*/
struct DummySendTaskFunction : public SendTaskFunction<void>
{
void operator()( int _ )
{
++_;
}
};
/**
* @brief Handle response functor which does nothing.
*/
struct DummyHandleResponseFunction : public HandleResponseFunction<void>
{
void operator()( int _ )
{
++_;
}
};
/**
* @brief Process task functor which does nothing.
*/
struct DummyProcessTaskFunction : public ProcessTaskFunction<void>
{
void operator()()
{
// nothing!
}
};
/**
* @brief Is finished functor which returns true everytime.
*/
struct DummyIsFinishedFunction : public IsFinishedFunction<void>
{
bool operator()()
{
return true;
}
};
/**
* @brief Job store containing all dummy functors and containing no data.
*/
struct DummyJobStore : public JobStore<void>
{
using JobStore<void>::_stf;
using JobStore<void>::_hrf;
using JobStore<void>::_ptf;
using JobStore<void>::_iff;
DummyJobStore()
{
_stf = new DummySendTaskFunction;
_stf->needDelete( true );
_hrf = new DummyHandleResponseFunction;
_hrf->needDelete( true );
_ptf = new DummyProcessTaskFunction;
_ptf->needDelete( true );
_iff = new DummyIsFinishedFunction;
_iff->needDelete( true );
}
void* data() { return 0; }
};
/**
* @brief Job to run after a Multi Job, so as to indicate that every workers should terminate.
*/
struct EmptyJob : public OneShotJob<void>
{
/**
* @brief Main EmptyJob ctor
*
* @param algo Assignment (scheduling) algorithm used.
* @param masterRank The rank of the master process.
*/
EmptyJob( AssignmentAlgorithm& algo, int masterRank ) :
OneShotJob<void>( algo, masterRank, *(new DummyJobStore) )
// the job store is deleted on destructor
{
// empty
}
~EmptyJob()
{
std::vector< int > idles = assignmentAlgo.idles();
for(unsigned i = 0, size = idles.size(); i < size; ++i)
{
comm.send( idles[i], Channel::Commands, Message::Kill );
}
delete & this->store;
}
};
/**
* @}
*/
}
}
# endif // __EO_TERMINATE_H__

166
eo/src/mpi/implMpi.cpp Normal file
View file

@ -0,0 +1,166 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include "implMpi.h"
namespace mpi
{
const int any_source = MPI_ANY_SOURCE;
const int any_tag = MPI_ANY_TAG;
environment::environment(int argc, char**argv)
{
MPI_Init(&argc, &argv);
}
environment::~environment()
{
MPI_Finalize();
}
status::status( const MPI_Status & s )
{
_source = s.MPI_SOURCE;
_tag = s.MPI_TAG;
_error = s.MPI_ERROR;
}
communicator::communicator( )
{
_rank = -1;
_size = -1;
_buf = 0;
_bufsize = -1;
}
communicator::~communicator()
{
if( _buf )
{
delete _buf;
_buf = 0;
}
}
int communicator::rank()
{
if ( _rank == -1 )
{
MPI_Comm_rank( MPI_COMM_WORLD, &_rank );
}
return _rank;
}
int communicator::size()
{
if ( _size == -1 )
{
MPI_Comm_size( MPI_COMM_WORLD, &_size );
}
return _size;
}
/*
* SEND / RECV INT
*/
void communicator::send( int dest, int tag, int n )
{
MPI_Send( &n, 1, MPI_INT, dest, tag, MPI_COMM_WORLD );
}
void communicator::recv( int src, int tag, int& n )
{
MPI_Status stat;
MPI_Recv( &n, 1, MPI_INT, src, tag, MPI_COMM_WORLD , &stat );
}
/*
* SEND / RECV STRING
*/
void communicator::send( int dest, int tag, const std::string& str )
{
int size = str.size() + 1;
send( dest, tag, size );
MPI_Send( (char*)str.c_str(), size, MPI_CHAR, dest, tag, MPI_COMM_WORLD);
}
void communicator::recv( int src, int tag, std::string& str )
{
int size = -1;
MPI_Status stat;
recv( src, tag, size );
if( _buf == 0 )
{
_buf = new char[ size ];
_bufsize = size;
} else if( _bufsize < size )
{
delete [] _buf;
_buf = new char[ size ];
_bufsize = size;
}
MPI_Recv( _buf, size, MPI_CHAR, src, tag, MPI_COMM_WORLD, &stat );
str.assign( _buf );
}
/*
* SEND / RECV Objects
*/
void communicator::send( int dest, int tag, const eoserial::Persistent & persistent )
{
eoserial::Object* obj = persistent.pack();
std::stringstream ss;
obj->print( ss );
delete obj;
send( dest, tag, ss.str() );
}
void communicator::recv( int src, int tag, eoserial::Persistent & persistent )
{
std::string asText;
recv( src, tag, asText );
eoserial::Object* obj = eoserial::Parser::parse( asText );
persistent.unpack( obj );
delete obj;
}
/*
* Other methods
*/
status communicator::probe( int src, int tag )
{
MPI_Status stat;
MPI_Probe( src, tag, MPI_COMM_WORLD , &stat );
return status( stat );
}
void communicator::barrier()
{
MPI_Barrier( MPI_COMM_WORLD );
}
void broadcast( communicator & comm, int value, int root )
{
MPI_Bcast( &value, 1, MPI_INT, root, MPI_COMM_WORLD );
}
}

322
eo/src/mpi/implMpi.h Normal file
View file

@ -0,0 +1,322 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EO_IMPL_MPI_HPP__
# define __EO_IMPL_MPI_HPP__
# include <mpi.h>
# include <serial/eoSerial.h>
/**
* This namespace contains reimplementations of some parts of the Boost::MPI API in C++, so as to be used in
* EO without any dependance to Boost. Historically, EO's parallelization module used the
* boost library to add a layer over MPI. After having noticed that just some functions
* were really used, we decided to reimplement our own C++-like implementation of MPI.
*
* Because the Boost::MPI API is really clean, we reused it in this module. However, all
* the functions of Boost::MPI were not used, hence a subset of the API is reused. For
* instance, users can just send integer, std::string or eoserial::Persistent objects;
* furthermore, only eoserial::Persistent objects can sent in a table.
*
* The documentation of the functions is exactly the same as the official Boost::MPI
* documentation. You can find it on www.boost.org/doc/libs/1_49_0/doc/html/mpi/
* The entities are here shortly described, if you need further details, don't hesitate
* to visit the boost URL.
*/
namespace mpi
{
/**
* @ingroup Parallel
* @{
*/
/**
* @brief Constant indicating that a message can come from any process.
*/
extern const int any_source;
/**
* @brief Constant indicating that a message can come from any tag (channel).
*/
extern const int any_tag;
/**
* @brief Wrapper class to have a MPI environment.
*
* Instead of calling MPI_Init and MPI_Finalize, it is only necessary to instantiate
* this class once, in the global context.
*/
class environment
{
public:
/**
* @brief Inits MPI context.
*
* @param argc Number of params in command line (same as one in main)
* @param argv Strings containing params (same as one in main)
*/
environment(int argc, char**argv);
/**
* @brief Closes MPI context.
*/
~environment();
};
/**
* @brief Wrapper class for MPI_Status
*
* Consists only in a C++ wrapper class, giving getters on status attributes.
*/
class status
{
public:
/**
* @brief Converts a MPI_Status into a status.
*/
status( const MPI_Status & s );
/**
* @brief Returns the tag of the associated communication.
*/
int tag() { return _tag; }
/**
* @brief Indicates which error number we obtained in the associated communication.
*/
int error() { return _error; }
/**
* @brief Returns the MPI rank of the source of the associated communication.
*/
int source() { return _source; }
private:
int _source;
int _tag;
int _error;
};
/**
* @brief Main object, used to send / receive messages, get informations about the rank and the size of the world,
* etc.
*/
class communicator
{
public:
/**
* Creates the communicator, using the whole world as a MPI_Comm.
*
* @todo Allow the user to precise which MPI_Comm to use
*/
communicator( );
~communicator();
/**
* @brief Returns the MPI rank of the current process.
*/
int rank();
/**
* @brief Returns the size of the MPI cluster.
*/
int size();
/*
* SEND / RECV INT
*/
/**
* @brief Sends an integer to dest on channel "tag".
*
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param n The integer to send
*/
void send( int dest, int tag, int n );
/*
* @brief Receives an integer from src on channel "tag".
*
* @param src MPI rank of the sender
* @param tag MPI tag of message
* @param n Where to save the received integer
*/
void recv( int src, int tag, int& n );
/*
* SEND / RECV STRING
*/
/**
* @brief Sends a string to dest on channel "tag".
*
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param str The std::string to send
*/
void send( int dest, int tag, const std::string& str );
/*
* @brief Receives a string from src on channel "tag".
*
* @param src MPI rank of the sender
* @param tag MPI tag of message
* @param std::string Where to save the received string
*/
void recv( int src, int tag, std::string& str );
/*
* SEND / RECV Objects
*/
/**
* @brief Sends an eoserial::Persistent to dest on channel "tag".
*
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param persistent The object to send (it must absolutely implement eoserial::Persistent)
*/
void send( int dest, int tag, const eoserial::Persistent & persistent );
/**
* @brief Sends an array of eoserial::Persistent to dest on channel "tag".
*
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param table The array of eoserial::Persistent objects
* @param size The number of elements to send (no check is done, the user has to be sure that the size won't
* overflow!)
*/
template< class T >
void send( int dest, int tag, T* table, int size )
{
// Puts all the values into an array
eoserial::Array* array = new eoserial::Array;
for( int i = 0; i < size; ++i )
{
array->push_back( table[i].pack() );
}
// Encapsulates the array into an object
eoserial::Object* obj = new eoserial::Object;
obj->add( "array", array );
std::stringstream ss;
obj->print( ss );
delete obj;
// Sends the object as a string
send( dest, tag, ss.str() );
}
/*
* @brief Receives an eoserial::Persistent object from src on channel "tag".
*
* @param src MPI rank of the sender
* @param tag MPI tag of message
* @param persistent Where to unpack the serialized object?
*/
void recv( int src, int tag, eoserial::Persistent & persistent );
/*
* @brief Receives an array of eoserial::Persistent from src on channel "tag".
*
* @param src MPI rank of the sender
* @param tag MPI tag of message
* @param table The table in which we're saving the received objects. It must have been allocated by the user,
* as no allocation is performed here.
* @param size The number of elements to receive (no check is done, the user has to be sure that the size won't
* overflow!)
*/
template< class T >
void recv( int src, int tag, T* table, int size )
{
// Receives the string which contains the object
std::string asText;
recv( src, tag, asText );
// Parses the object and retrieves the table
eoserial::Object* obj = eoserial::Parser::parse( asText );
eoserial::Array* array = static_cast<eoserial::Array*>( (*obj)["array"] );
// Retrieves all the values from the array
for( int i = 0; i < size; ++i )
{
eoserial::unpackObject( *array, i, table[i] );
}
delete obj;
}
/*
* Other methods
*/
/**
* @brief Wrapper for MPI_Probe
*
* Waits for a message to come from process having rank src, on the channel
* tag.
*
* @param src MPI rank of the sender (any_source if it can be any sender)
* @param tag MPI tag of the expected message (any_tag if it can be any tag)
*/
status probe( int src = any_source, int tag = any_tag );
/**
* @brief Wrapper for MPI_Barrier
*
*
*/
void barrier();
private:
int _rank;
int _size;
char* _buf; // temporary buffer for sending and receiving strings. Avoids reallocations
int _bufsize; // size of the above temporary buffer
};
/**
* @brief Wrapper for MPI_Bcast
*
* Broadcasts an integer value on the communicator comm, from the process having the MPI rank root.
*
* @param comm The communicator on which to broadcast
* @param value The integer value to send
* @param root The MPI rank of the broadcaster
*
* @todo Actually comm isn't used and broadcast is performed on the whole MPI_COMM_WORLD. TODO: Use comm instead
*/
void broadcast( communicator & comm, int value, int root );
/**
* @}
*/
} // namespace mpi
# endif //__EO_IMPL_MPI_HPP__

View file

@ -15,49 +15,49 @@
#
# ----------------------------------------------------------------------------
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
cmake_minimum_required(VERSION 2.8)
PROJECT(PyEO)
project(PyEO)
FIND_PACKAGE(Boost 1.42 COMPONENTS python)
FIND_PACKAGE(PythonLibs)
find_package(Boost 1.42 COMPONENTS python)
find_package(PythonLibs)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${PYTHON_INCLUDE_PATH})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
IF(APPLE)
if(APPLE)
# osx internal
FIND_LIBRARY(APPLE_CARBON Carbon)
ENDIF(APPLE)
find_library(APPLE_CARBON Carbon)
endif(APPLE)
# includes
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
#INCLUDE_DIRECTORIES(../)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
#include_directories(../)
# source
FILE(GLOB SOURCES *.cpp)
file(GLOB SOURCES *.cpp)
# EO dependencies
SET(EO_SOURCES
${EO_SOURCE_DIR}/src/eoFunctorStore.cpp
${EO_SOURCE_DIR}/src/utils/eoLogger.cpp
${EO_SOURCE_DIR}/src/utils/eoParallel.cpp
set(EO_SOURCES
${EO_SRC_DIR}/src/eoFunctorStore.cpp
${EO_SRC_DIR}/src/utils/eoLogger.cpp
${EO_SRC_DIR}/src/utils/eoParallel.cpp
)
# shared library
ADD_LIBRARY(PyEO MODULE ${SOURCES} ${EO_SOURCES})
INSTALL(TARGETS PyEO LIBRARY DESTINATION ${LIB} COMPONENT libraries)
add_library(PyEO MODULE ${SOURCES} ${EO_SOURCES})
install(TARGETS PyEO LIBRARY DESTINATION local/${LIB} COMPONENT libraries)
# python 2.5 must have pyd
IF(WIN32 AND NOT CYGWIN)
SET_TARGET_PROPERTIES(PyEO PROPERTIES SUFFIX ".pyd")
ENDIF(WIN32 AND NOT CYGWIN)
if(WIN32 AND NOT CYGWIN)
set_target_properties(PyEO PROPERTIES SUFFIX ".pyd")
endif(WIN32 AND NOT CYGWIN)
# add the libs
IF(APPLE)
TARGET_LINK_LIBRARIES(PyEO ${APPLE_CARBON} ${PYTHON_LIBRARY} ${Boost_LIBRARIES})
ELSE(APPLE)
TARGET_LINK_LIBRARIES(PyEO ${PYTHON_LIBRARY} ${Boost_LIBRARIES})
ENDIF(APPLE)
if(APPLE)
target_link_libraries(PyEO ${APPLE_CARBON} ${PYTHON_LIBRARY} ${Boost_LIBRARIES})
else(APPLE)
target_link_libraries(PyEO ${PYTHON_LIBRARY} ${Boost_LIBRARIES})
endif(APPLE)

58
eo/src/serial/Array.cpp Normal file
View file

@ -0,0 +1,58 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include "Array.h"
namespace eoserial
{
std::ostream& Array::print( std::ostream& out ) const
{
out << "[";
bool first = true;
for (ArrayChildren::const_iterator it = begin(),
end = this->end();
it != end;
++it)
{
if ( first )
{
first = false;
} else {
out << ", ";
}
(*it)->print( out );
}
out << "]\n";
return out;
}
Array::~Array()
{
for (ArrayChildren::iterator it = begin(),
end = this->end();
it != end;
++it)
{
delete *it;
}
}
} // namespace eoserial

170
eo/src/serial/Array.h Normal file
View file

@ -0,0 +1,170 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_ARRAY_H__
# define __EOSERIAL_ARRAY_H__
# include <vector>
# include "Entity.h"
# include "Serializable.h"
# include "Object.h"
namespace eoserial
{
// Forward declaration for below declarations.
class Array;
/*
* Declarations of functions present in Utils.h
* These are put here to avoid instead of including the file Utils.h, which would
* cause a circular inclusion.
*/
template< class T >
void unpack( const Array & array, unsigned int index, T & value );
void unpackObject( const Array & array, unsigned int index, Persistent & value );
template< class Container, template<class> class UnpackAlgorithm >
void unpackArray( const Array & array, unsigned int index, Container & container );
/**
* @brief Represents a JSON array.
*
* Wrapper for an array, so as to be used as a JSON object.
*
* @ingroup Serialization
*/
class Array : public eoserial::Entity, public std::vector< eoserial::Entity* >
{
protected:
typedef std::vector< eoserial::Entity* > ArrayChildren;
public:
/**
* @brief Adds the serializable object as a JSON object.
* @param obj Object which implemnets JsonSerializable.
*/
void push_back( const eoserial::Printable* obj )
{
ArrayChildren::push_back( obj->pack() );
}
/**
* @brief Proxy for vector::push_back.
*/
void push_back( eoserial::Entity* json )
{
ArrayChildren::push_back( json );
}
/**
* @brief Prints the JSON array into the given stream.
* @param out The stream
*/
virtual std::ostream& print( std::ostream& out ) const;
/**
* @brief Dtor
*/
~Array();
/*
* The following parts allows the user to automatically deserialize an eoserial::Array into a
* standard container, by giving the algorithm which will be used to deserialize contained entities.
*/
/**
* @brief Functor which determines how to retrieve the real value contained in a eoserial::Entity at
* a given place.
*
* It will be applied for each contained variable in the array.
*/
template<class Container>
struct BaseAlgorithm
{
/**
* @brief Main operator.
*
* @param array The eoserial::Array from which we're reading.
* @param i The index of the contained value.
* @param container The standard (STL) container in which we'll push back the read value.
*/
virtual void operator()( const eoserial::Array& array, unsigned int i, Container & container ) const = 0;
};
/**
* @brief BaseAlgorithm for retrieving primitive variables.
*
* This one should be used to retrieve primitive (and types which implement operator>>) variables, for instance
* int, double, std::string, etc...
*/
template<typename C>
struct UnpackAlgorithm : public BaseAlgorithm<C>
{
void operator()( const eoserial::Array& array, unsigned int i, C & container ) const
{
typename C::value_type t;
unpack( array, i, t );
container.push_back( t );
}
};
/**
* @brief BaseAlgorithm for retrieving eoserial::Persistent objects.
*
* This one should be used to retrieve objects which implement eoserial::Persistent.
*/
template<typename C>
struct UnpackObjectAlgorithm : public BaseAlgorithm<C>
{
void operator()( const eoserial::Array& array, unsigned int i, C & container ) const
{
typename C::value_type t;
unpackObject( array, i, t );
container.push_back( t );
}
};
/**
* @brief General algorithm for array deserialization.
*
* Applies the BaseAlgorithm to each contained variable in the eoserial::Array.
*/
template<class Container, template<class T> class UnpackAlgorithm>
inline void deserialize( Container & array )
{
UnpackAlgorithm< Container > algo;
for( unsigned int i = 0, size = this->size();
i < size;
++i)
{
algo( *this, i, array );
}
}
};
} // namespace eoserial
# endif // __EOSERIAL_ARRAY_H__

View file

@ -0,0 +1,35 @@
######################################################################################
### 1) Include the sources
######################################################################################
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Define the eoserial target
######################################################################################
set(EOSERIAL_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib)
set(LIBRARY_OUTPUT_PATH ${EOSERIAL_LIB_OUTPUT_PATH})
set(EOSERIAL_SOURCES
Array.cpp
Object.cpp
Parser.cpp
String.cpp
)
add_library(eoserial STATIC ${EOSERIAL_SOURCES})
install(TARGETS eoserial ARCHIVE DESTINATION lib COMPONENT libraries)
file(GLOB HDRS *.h)
install(FILES ${HDRS} DESTINATION include/eo/serial COMPONENT headers)
######################################################################################
### 3) Optionnal
######################################################################################
set(EOSERIAL_VERSION ${GLOBAL_VERSION})
set_target_properties(eoserial PROPERTIES VERSION "${EOSERIAL_VERSION}")
######################################################################################

70
eo/src/serial/Entity.h Normal file
View file

@ -0,0 +1,70 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_ENTITY_H__
# define __EOSERIAL_ENTITY_H__
# include <iostream> // ostream
/**
* @brief Contains all the necessary entities to serialize eo objects into JSON objects.
*
* Allows serialization from user objects into JSON objects, if they implement the interface
* eoserial::Serializable or eoserial::Persistent. The following user objects can be serialized:
* - primitive types (int, std::string, ...), in particular every type that can be written into a
* std::stringstream.
* - objects which implement eoserial::Serializable.
* - array of serializable things (primitive or serializable objects).
*
* @ingroup Utilities
* @defgroup Serialization Serialization helpers
**/
namespace eoserial
{
/**
* @brief JSON entity
*
* This class represents a JSON entity, which can be JSON objects,
* strings or arrays. It is the base class for the JSON hierarchy.
*
* @ingroup Serialization
*/
class Entity
{
public:
/**
* Virtual dtor (base class).
*/
virtual ~Entity() { /* empty */ }
/**
* @brief Prints the content of a JSON object into a stream.
* @param out The stream in which we're printing.
*/
virtual std::ostream& print( std::ostream& out ) const = 0;
};
} // namespace eoserial
# endif // __ENTITY_H__

60
eo/src/serial/Object.cpp Normal file
View file

@ -0,0 +1,60 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include "Object.h"
using namespace eoserial;
namespace eoserial
{
std::ostream& Object::print( std::ostream& out ) const
{
out << '{';
bool first = true;
for(JsonValues::const_iterator it = begin(), end = this->end();
it != end;
++it)
{
if ( first )
{
first = false;
} else {
out << ", ";
}
out << '"' << it->first << "\":"; // key
it->second->print( out ); // value
}
out << "}\n";
return out;
}
Object::~Object()
{
for(JsonValues::iterator it = begin(), end = this->end();
it != end;
++it)
{
delete it->second;
}
}
} // namespace eoserial

88
eo/src/serial/Object.h Normal file
View file

@ -0,0 +1,88 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_OBJECT_H__
# define __EOSERIAL_OBJECT_H__
# include <map>
# include <string>
# include "Entity.h"
# include "Serializable.h"
namespace eoserial
{
/**
* @brief JSON Object
*
* This class represents a JSON object, which is basically a dictionnary
* of keys (strings) and values (JSON entities).
*
* @ingroup Serialization
*/
class Object : public eoserial::Entity, public std::map< std::string, eoserial::Entity* >
{
public:
typedef std::map<std::string, eoserial::Entity*> JsonValues;
/**
* @brief Adds a pair into the JSON object.
* @param key The key associated with the eoserial object
* @param json The JSON object as created with framework.
*/
void add( const std::string& key, eoserial::Entity* json )
{
(*this)[ key ] = json;
}
/**
* @brief Adds a pair into the JSON object.
* @param key The key associated with the eoserial object
* @param obj A JSON-serializable object
*/
void add( const std::string& key, const eoserial::Printable* obj )
{
(*this)[ key ] = obj->pack();
}
/**
* @brief Deserializes a Serializable class instance from this JSON object.
* @param obj The object we want to rebuild.
*/
void deserialize( eoserial::Persistent & obj )
{
obj.unpack( this );
}
/**
* @brief Dtor
*/
~Object();
/**
* @brief Prints the content of a JSON object into a stream.
*/
virtual std::ostream& print( std::ostream& out ) const;
};
} // namespace eoserial
# endif // __EOSERIAL_OBJECT_H__

171
eo/src/serial/Parser.cpp Normal file
View file

@ -0,0 +1,171 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include <string>
# include "Parser.h"
# include "Array.h"
# include "Object.h"
# include "String.h"
// in debug mode only
// # define DEBUG(x) std::cout << x << std::endl;
# define DEBUG(x)
using namespace eoserial;
namespace eoserial
{
/**
* @brief Parses a string contained between double quotes.
*
* Strings can contain escaped double quotes.
* @param str The string we're parsing.
* @param pos The index of current position in parsed string.
* This index will be updated so as to allow the parser to
* continue.
*/
static std::string parseString(const std::string& str, size_t & pos)
{
// example : "hello"
// example 2 : "\"world\""
// for hello:
// firstQuote == 0, secondQuote == 6
// sub string should be from firstQuote+1 to secondQuote-1
// so its size should be (secondQuote-1 -(firstQuote+1) + 1)
std::string value;
size_t firstQuote = str.find( '"', pos );
size_t secondQuote;
/* instead of just seeking the second quote, we need to ensure
// that there is no escaped quote before this one.
// actually this is harder than that. Using backslashes
// to escape double quotes mean that backslashes have to be
// escaped to.
// example : "text\\" to symbolize : text\
// example : "text\\\" to symbolize : text\"
// In fact, we should find if number of backslashes is odd; in this case,
// the double quotes are escaped and we should find the next one.
*/
int backslashesCount;
do {
++pos;
secondQuote = str.find( '"', pos );
size_t i = secondQuote - 1;
// Find the backslashes
backslashesCount = 0;
while ( str[ i ] == '\\' )
{
--i;
++backslashesCount;
}
pos = secondQuote;
} while( backslashesCount % 2 == 1 );
value = str.substr( firstQuote+1, secondQuote-firstQuote-1 );
pos = secondQuote + 1;
return value;
}
/**
* @brief Moves the given index pos to the next character which is
* neither a coma, a space nor a new line.
*
* @param str The string in which we want to ignores those characters.
* @param pos The index of current position in parsed string.
*/
static void ignoreChars(const std::string& str, size_t & pos)
{
// ignore white spaces and comas
for (char current = str[ pos ];
current == ',' || current == ' ' || current == '\n';
current = str[ ++pos ]);
}
String* Parser::parseJsonString(const std::string & str, size_t & pos)
{
return new String( parseString( str, pos ) );
}
Object* Parser::parse(const std::string & str)
{
size_t initial(0); // we begin at position 0
return static_cast<Object*>( parseRight(str, initial) );
}
Entity* Parser::parseRight(const std::string & str, size_t & pos)
{
Entity* value = 0;
if ( str[ pos ] == '{' )
{
// next one is an object
DEBUG("We read an object.")
Object* obj = new Object;
pos += 1;
while( pos < str.size() && str[ pos ] != '}' )
{
parseLeft( str, pos, obj );
ignoreChars( str, pos );
}
DEBUG("We just finished to read an object ! ")
pos += 1; // we're on the }, go to the next char
value = obj;
}
else if ( str[ pos ] == '"' )
{
// next one is a string
DEBUG("We read a string")
value = parseJsonString( str, pos );
}
else if ( str[ pos ] == '[' )
{
// next one is an array
DEBUG("We read an array")
Array* array = new Array;
pos += 1;
while( pos < str.size() && str[ pos ] != ']' )
{
Entity* child = parseRight( str, pos );
if ( child )
array->push_back( child );
}
DEBUG("We've finished to read our array.")
pos += 1; // we're on the ], go to the next char
value = array;
}
ignoreChars( str, pos );
return value;
}
void Parser::parseLeft(const std::string & str, size_t & pos, Object* eoserial)
{
std::string key = parseString(str, pos);
++pos; // the colon
DEBUG("We've read the key ")
(*eoserial)[ key ] = parseRight( str, pos );
}
} // namespace eoserial

103
eo/src/serial/Parser.h Normal file
View file

@ -0,0 +1,103 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_PARSER_H__
# define __EOSERIAL_PARSER_H__
# include "Entity.h"
# include "String.h"
# include "Object.h"
/**
* @file Parser.h
*
* This file contains a tiny JSON parser used in DAE. This parser just handles
* a subset of JSON grammar, with the following restrictions :
* - all strings must be surrounded by double quotes.
* - everything which is not an object or an array is considered to be a string
* (even integers, booleans,...).
* - no syntax check is done. We trust the programmer and he has to ensure that
* every JSON string he produces is valid.
*
* @author Benjamin BOUVIER
*/
namespace eoserial
{
/**
* @brief Parser from a JSON source.
*
* This parser does just retrieve values and does NOT check the structure of
* the input. This implies that if the input is not correct, the result is undefined
* and can result to a failure on execution.
*
* @ingroup Serialization
*/
class Parser
{
public:
/**
* @brief Parses the given string and returns the JSON object read.
*/
static eoserial::Object* parse(const std::string & str);
protected:
/**
* @brief Parses the right part of a JSON object as a string.
*
* The right part of an object can be a string (for instance :
* "key":"value"), a JSON array (for instance: "key":["1"]) or
* another JSON object (for instance: "key":{"another_key":"value"}).
*
* The right parts are found after keys (which are parsed by parseLeft)
* and in arrays.
*
* @param str The string we're parsing.
* @param pos The index of the current position in the string.
* @return The JSON object matching the right part.
*/
static eoserial::Entity* parseRight(const std::string & str, size_t & pos);
/**
* @brief Parses the left value of a key-value pair, which is the key.
*
* @param str The string we're parsing.
* @param pos The index of the current position in the string.
* @param json The current JSON object for which we're adding a key-value pair.
*/
static void parseLeft(const std::string & str, size_t & pos, eoserial::Object* json);
/**
* @brief Retrieves a string in a JSON content.
*
* @param str The string we're parsing.
* @param pos The index of the current position of parsing,
* which will be updated.
*/
static eoserial::String* parseJsonString(const std::string & str, size_t & pos);
};
} // namespace eoserial
# endif // __EOSERIAL_PARSER_H__

View file

@ -0,0 +1,66 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_SERIALIZABLE_H__
# define __EOSERIAL_SERIALIZABLE_H__
namespace eoserial
{
class Object; // to avoid recursive inclusion with JsonObject
/**
* @brief Interface showing that object can be written to a eoserial type
* (currently JSON).
*
* @ingroup Serialization
*/
class Printable
{
public:
/**
* @brief Serializes the object to JSON format.
* @return A JSON object created with new.
*/
virtual eoserial::Object* pack() const = 0;
};
/**
* @brief Interface showing that object can be eoserialized (written and read
* from an input).
*
* Note : Persistent objects should have a default non-arguments constructor.
*
* @ingroup Serialization
*/
class Persistent : public Printable
{
public:
/**
* @brief Loads class fields from a JSON object.
* @param json A JSON object. Programmer doesn't have to delete it, it
* is automatically done.
*/
virtual void unpack(const eoserial::Object* json) = 0;
};
} // namespace eoserial
# endif // __EOSERIAL_SERIALIZABLE_H__

View file

@ -1,7 +1,5 @@
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
/*
(c) Thales group, 2010
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -16,21 +14,19 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Caner Candan <caner.candan@thalesgroup.com>
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# include "String.h"
#ifndef EO_PARSER_LOGGER_H
#define EO_PARSER_LOGGER_H
namespace eoserial
{
std::ostream& String::print( std::ostream& out ) const
{
out << '"' << *this << '"';
return out;
}
} // namespace eoserial
#include "eoParser.h"
#warning "[eoParserLogger] is deprecated"
typedef eoParser eoParserLogger;
#endif // !EO_PARSER_LOGGER_H

103
eo/src/serial/String.h Normal file
View file

@ -0,0 +1,103 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_STRING_H__
# define __EOSERIAL_STRING_H__
# include <string>
# include <sstream>
# include <limits>
# include "Entity.h"
namespace eoserial
{
/**
* @brief JSON String
*
* Wrapper for string, so as to be used as a JSON object.
*
* @ingroup Serialization
*/
class String : public eoserial::Entity, public std::string
{
public:
/**
* @brief Default ctor.
* @param str The string we want to wrap.
*/
String( const std::string& str ) : std::string( str ) {}
/**
* @brief Ctor used only when parsing.
*/
String( ) {}
/**
* @brief Prints out the string.
*/
virtual std::ostream& print( std::ostream& out ) const;
/**
* @brief Deserializes the current String into a given primitive type value.
* @param value The value in which we're writing.
*/
template<class T>
inline void deserialize( T & value );
protected:
// Copy and reaffectation are forbidden
explicit String( const String& _ );
String& operator=( const String& _ );
};
/**
* @brief Casts a eoserial::String into a primitive value, or in a type which at
* least overload operator>>.
*
* @param value A reference to the variable we're writing into.
*
* It's not necessary to specify the variable type, which can be infered by compiler when
* invoking.
*/
template<class T>
inline void String::deserialize( T & value )
{
std::stringstream ss;
ss.precision(std::numeric_limits<double>::digits10 + 1);
ss << *this;
ss >> value;
}
/**
* @brief Specialization for strings, which don't need to be converted through
* a stringstream.
*/
template<>
inline void String::deserialize( std::string & value )
{
value = *this;
}
} // namespace eoserial
# endif // __EOSERIAL_STRING_H__

189
eo/src/serial/Utils.h Normal file
View file

@ -0,0 +1,189 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_UTILS_H__
# define __EOSERIAL_UTILS_H__
# include "Array.h"
# include "Object.h"
# include "String.h"
namespace eoserial
{
/* ***************************
* DESERIALIZATION FUNCTIONS *
*****************************
These functions are useful for casting eoserial::objects into simple, primitive
variables or into class instance which implement eoserial::Persistent.
The model is always quite the same :
- the first argument is the containing object (which is a eoserial::Entity,
an object or an array)
- the second argument is the key or index,
- the last argument is the value in which we're writing.
*/
template< class T >
inline void unpack( const Object & obj, const std::string & key, T & value )
{
static_cast<String*>( obj.find( key )->second )->deserialize( value );
}
inline void unpackObject( const Object & obj, const std::string & key, Persistent & value )
{
static_cast<Object*>( obj.find( key )->second )->deserialize( value );
}
template< class Container, template<class> class UnpackAlgorithm >
inline void unpackArray( const Object & obj, const std::string & key, Container & array )
{
static_cast<Array*>( obj.find( key )->second )->deserialize< Container, UnpackAlgorithm >( array );
}
template< class T >
inline void unpack( const Array & array, unsigned int index, T & value )
{
static_cast<String*>( array[ index ] )->deserialize( value );
}
inline void unpackObject( const Array & array, unsigned int index, Persistent & value )
{
static_cast<Object*>( array[ index ] )->deserialize( value );
}
template< class Container, template<class> class UnpackAlgorithm >
inline void unpackArray( const Array & array, unsigned int index, Container & container )
{
static_cast<Array*>( array[ index ] )->deserialize< Container, UnpackAlgorithm >( container );
}
/* *****************************
*** SERIALIZATION FUNCTIONS ***
*******************************
These functions are useful for casting classic objects and
eoserial::Persistent objects into eoserial entities which
can be manipulated by the framework.
*/
/**
* @brief Casts a value of a stream-serializable type (i.e, which implements
* operator <<) into a JsonString.
*
* This is used when serializing the objects : all primitives types should be
* converted into strings to get more easily manipulated.
*
* @param value The value we're converting.
* @return JsonString wrapper for the value.
*/
template <typename T>
String* make( const T & value )
{
std::stringstream ss;
ss.precision(std::numeric_limits<double>::digits10 + 1);
ss << value;
return new String( ss.str() );
}
/**
* @brief Specialization for strings : no need to convert as they're still
* usable as strings.
*/
template<>
inline String* make( const std::string & value )
{
return new String( value );
}
/*
* These functions are useful for automatically serializing STL containers into
* eoserial arrays which could be used by the framework.
**/
/**
* @brief Functor which explains how to push the value into the eoserial::Array.
*/
template< class T >
struct PushAlgorithm
{
/**
* @brief Main operator.
*
* @param array The eoserial::array in which we're writing.
* @param value The variable we are writing.
*/
virtual void operator()( Array & array, const T & value ) = 0;
};
/**
* @brief Push algorithm for primitive variables.
*
* This one should be used when inserting primitive (and types which implement
* operator<<) variables.
*/
template< class T >
struct MakeAlgorithm : public PushAlgorithm<T>
{
void operator()( Array & array, const T & value )
{
array.push_back( make( value ) );
}
};
/**
* @brief Push algorithm for eoserial::Persistent variables.
*/
template< class T >
struct SerializablePushAlgorithm : public PushAlgorithm<T>
{
void operator()( Array & array, const T & obj )
{
// obj address is not saved into array.push_back.
array.push_back( &obj );
}
};
/**
* @brief Casts a STL container (vector<int> or list<std::string>, for instance)
* into a eoserial::Array.
*
* @þaram PushAlgorithm The algorithm used for inserting new element in the eoserial::Array.
* This algorithm is directly called, so it is its own charge to invoke push_back on the
* eoserial::Array.
*/
template< class Container, template<class> class PushAlgorithm >
Array* makeArray( const Container & array )
{
Array* returned_array = new Array;
typedef typename Container::const_iterator iterator;
typedef typename Container::value_type Type;
PushAlgorithm< Type > algo;
for (
iterator it = array.begin(), end = array.end();
it != end;
++it)
{
algo( *returned_array, *it );
}
return returned_array;
}
} // namespace eoserial
# endif //__EOSERIAL_UTILS_H__

33
eo/src/serial/eoSerial.h Normal file
View file

@ -0,0 +1,33 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EOSERIAL_HEADERS__
# define __EOSERIAL_HEADERS__
# include "Object.h"
# include "Serializable.h"
# include "Array.h"
# include "Object.h"
# include "String.h"
# include "Parser.h"
# include "Utils.h"
# endif // __EOSERIAL_HEADERS__

View file

@ -0,0 +1,8 @@
{"a":"b",
"obj":
{"obj_a":"obj_}b","subobj_a":
{"subk":"subv"}
},
"c":"d",
"array":["1","2",{"\"array\"_obj\"":"array_ov]"}, ["3"], "4"]
}

View file

@ -2,17 +2,17 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Define the ga target
######################################################################################
SET(EOUTILS_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
SET(LIBRARY_OUTPUT_PATH ${EOUTILS_LIB_OUTPUT_PATH})
set(EOUTILS_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib)
set(LIBRARY_OUTPUT_PATH ${EOUTILS_LIB_OUTPUT_PATH})
SET(EOUTILS_SOURCES
set(EOUTILS_SOURCES
eoData.cpp
eoFileMonitor.cpp
eoGnuplot.cpp
@ -32,15 +32,15 @@ SET(EOUTILS_SOURCES
eoSignal.cpp
)
ADD_LIBRARY(eoutils STATIC ${EOUTILS_SOURCES})
INSTALL(TARGETS eoutils ARCHIVE DESTINATION ${LIB} COMPONENT libraries)
add_library(eoutils STATIC ${EOUTILS_SOURCES})
install(TARGETS eoutils ARCHIVE DESTINATION local/${LIB} COMPONENT libraries)
######################################################################################
### 3) Optionnal
######################################################################################
SET(EOUTILS_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(eoutils PROPERTIES VERSION "${EOUTILS_VERSION}")
set(EOUTILS_VERSION ${GLOBAL_VERSION})
set_target_properties(eoutils PROPERTIES VERSION "${EOUTILS_VERSION}")
######################################################################################

View file

@ -116,7 +116,7 @@ namespace eo
*/
struct file
{
file(const std::string f);
explicit file(const std::string f);
const std::string _f;
};
@ -126,8 +126,8 @@ namespace eo
*/
struct setlevel
{
setlevel(const std::string v);
setlevel(const Levels lvl);
explicit setlevel(const std::string v);
explicit setlevel(const Levels lvl);
const std::string _v;
const Levels _lvl;
};

View file

@ -37,6 +37,7 @@ eoMonitor& eoOStreamMonitor::operator()(void)
} // if firstime
// ok, now the real saving. write out
// FIXME deprecated, remove in next release
//! @todo old verbose formatting, do we still need it?
/*
for (iterator it = vec.begin (); it != vec.end (); ++it) {

View file

@ -44,14 +44,17 @@ Authors:
class eoOStreamMonitor : public eoMonitor
{
public :
eoOStreamMonitor( std::ostream & _out, bool /*_verbose*/=true, std::string _delim = "\t", unsigned int _width=20, char _fill=' ' ) :
/* FIXME remove in next release
eoOStreamMonitor( std::ostream & _out, bool _verbose=true, std::string _delim = "\t", unsigned int _width=20, char _fill=' ' ) :
out(_out), delim(_delim), width(_width), fill(_fill), firsttime(true)
{
#ifndef DEPRECATED_MESSAGES
eo::log << eo::warnings << "WARNING: the use of the verbose parameter in eoOStreamMonitor constructor is deprecated and will be removed in the next release" << std::endl;
#pragma message "WARNING: the use of the verbose parameter in eoOStreamMonitor constructor is deprecated and will be removed in the next release"
#endif // !DEPRECATED_MESSAGES
}
*/
eoOStreamMonitor( std::ostream & _out, std::string _delim = "\t", unsigned int _width=20, char _fill=' ' ) :
out(_out), delim(_delim), width(_width), fill(_fill), firsttime(true)

View file

@ -21,22 +21,25 @@
Contact: http://eodev.sourceforge.net
Authors:
Caner Candan <caner.candan@thalesgroup.com>
Caner Candan <caner.candan@thalesgroup.com>
*/
#ifdef _OPENMP
#include <omp.h>
#endif
#include "eoParallel.h"
#include "eoLogger.h"
eoParallel::eoParallel() :
_isEnabled( false, "parallelize-loop", "Enable memory shared parallelization into evaluation's loops", '\0' ),
_isDynamic( false, "parallelize-dynamic", "Enable dynamic memory shared parallelization", '\0' ),
_isDynamic( true, "parallelize-dynamic", "Enable dynamic memory shared parallelization", '\0' ),
_prefix( "results", "parallelize-prefix", "Here's the prefix filename where the results are going to be stored", '\0' ),
_nthreads( 0, "parallelize-nthreads", "Define the number of threads you want to use, nthreads = 0 means you want to use all threads available", '\0' ),
_enableResults( false, "parallelize-enable-results", "Enable the generation of results", '\0' ),
_doMeasure( false, "parallelize-do-measure", "Do some measures during execution", '\0' ),
_packetSize( 1U, "parallelize-packet-size", "Number of elements which should be sent in a single message during a parallel evaluation based on message passing.", '\0'),
_t_start(0)
{
}
@ -90,6 +93,7 @@ void eoParallel::_createParameters( eoParser& parser )
parser.processParam( _nthreads, section );
parser.processParam( _enableResults, section );
parser.processParam( _doMeasure, section );
parser.processParam( _packetSize, section );
}
void make_parallel(eoParser& parser)

View file

@ -20,8 +20,7 @@
Contact: http://eodev.sourceforge.net
Authors:
Caner Candan <caner.candan@thalesgroup.com>
Caner Candan <caner.candan@thalesgroup.com>
*/
/** @defgroup Parallel Parallel
@ -54,6 +53,7 @@ public:
std::string prefix() const;
inline unsigned int nthreads() const { return _nthreads.value(); }
inline unsigned int packetSize() const { return _packetSize.value(); }
inline bool enableResults() const { return _enableResults.value(); }
inline bool doMeasure() const { return _doMeasure.value(); }
@ -70,6 +70,7 @@ private:
eoValueParam<unsigned int> _nthreads;
eoValueParam<bool> _enableResults;
eoValueParam<bool> _doMeasure;
eoValueParam<unsigned int> _packetSize;
double _t_start;
};

View file

@ -150,7 +150,8 @@ public :
initialize(2*s);
}
/** Re-initializes the Random Number Generator
/* FIXME remove in next release
** Re-initializes the Random Number Generator
This is the traditional seeding procedure. This version is deprecated and
only provided for compatibility with old code. In new projects you should
@ -159,11 +160,12 @@ public :
@see reseed for details on usage of the seeding value.
@version old version (deprecated)
*/
*
void oldReseed(uint32_t s)
{
initialize(s);
}
*/
/** Random number from unifom distribution

View file

@ -32,6 +32,7 @@ Contact: http://eodev.sourceforge.net
#ifndef _eoStat_h
#define _eoStat_h
#include <iostream>
#include <numeric> // accumulate
#include <eoFunctor.h>
@ -176,18 +177,27 @@ private :
};
/**
Average fitness + Std. dev. of a population, fitness needs to be scalar.
Average fitness + Std. dev. of a population, fitness HAVE TO BE to be scalar.
*/
template <class EOT>
class eoSecondMomentStats : public eoStat<EOT, std::pair<double, double> >
// FIXME find a way to use generic Fitness types instead of scala fitness here :
// class eoSecondMomentStats : public eoStat<EOT, std::pair<typename EOT::Fitness, typename EOT::Fitness> >
// Here, I failed to find a way to overload eoValueParam::getValue and setValue,
// because there is no way to use the partial specializations located in eoParam.h
// Indeed, eoValueParam is templatized on a ValueType, but the getValue signature does not
// contain this type.
// Thus, in order to use partial specializations the user would have to specify getValue<ValueType>(),
// which is not the case in most of the existing code.
// Overloading getValue in this class does not seems to work, the call falls to eoValueParam::getValue
// and fails on the output stream.
class eoSecondMomentStats : public eoStat<EOT, std::pair<double,double> >
{
public :
// typedef typename EOT::Fitness FitT;
typedef double FitT;
using eoStat<EOT, std::pair<double, double> >::value;
typedef typename EOT::Fitness fitness_type;
typedef std::pair<double, double> SquarePair;
using eoStat<EOT, std::pair<FitT, FitT> >::value;
typedef std::pair<FitT, FitT> SquarePair;
eoSecondMomentStats(std::string _description = "Average & Stdev")
: eoStat<EOT, SquarePair>(std::make_pair(0.0,0.0), _description)
@ -195,7 +205,7 @@ public :
static SquarePair sumOfSquares(SquarePair _sq, const EOT& _eo)
{
double fitness = _eo.fitness();
FitT fitness = _eo.fitness();
_sq.first += fitness;
_sq.second += fitness * fitness;
@ -211,9 +221,11 @@ public :
value().second = sqrt( (result.second - n * value().first * value().first) / (n - 1.0)); // stdev
}
virtual std::string className(void) const { return "eoSecondMomentStats"; }
virtual std::string className(void) const { return "eoSecondMomentStats"; }
};
/**
The n_th element fitness in the population (see eoBestFitnessStat)
*/
@ -244,6 +256,7 @@ public :
virtual std::string className(void) const { return "eoNthElementFitnessStat"; }
private :
/* Very old code...
struct CmpFitness
{
CmpFitness(unsigned _whichElement, bool _maxim) : whichElement(_whichElement), maxim(_maxim) {}
@ -259,6 +272,7 @@ private :
unsigned whichElement;
bool maxim;
};
*/
// for everything else
template <class T>
@ -329,6 +343,7 @@ public:
private :
/* Very old code...
struct CmpFitness
{
CmpFitness(unsigned _which, bool _maxim) : which(_which), maxim(_maxim) {}
@ -344,6 +359,7 @@ private :
unsigned which;
bool maxim;
};
*/
// default
template<class T>
@ -356,6 +372,39 @@ private :
/** @example t-eoSSGA.cpp
*/
/** Keep the best individual found so far
*/
template <class EOT>
class eoBestIndividualStat : public eoStat<EOT, EOT>
{
public:
using eoStat<EOT, EOT>::value;
eoBestIndividualStat(std::string _description = "BestIndiv ")
: eoStat<EOT, EOT>( EOT(), _description )
{}
void operator()(const eoPop<EOT>& pop)
{
EOT best = pop.best_element();
// on the first call, value() is invalid
if( value().invalid() ) {
// thus we cannot compare it to something else
value() = best;
} else {
// keep the best individual found so far
if( best.fitness() > value().fitness() ) {
value() = best;
}
}
}
virtual std::string className(void) const { return "eoBestIndividualStat"; }
};
template <class EOT>
class eoDistanceStat : public eoStat<EOT, double>
{

View file

@ -18,7 +18,7 @@ using namespace std;
void removeComment(string& str, string comment)
void eoState::removeComment(string& str, string comment)
{
string::size_type pos = str.find(comment);
@ -28,21 +28,23 @@ void removeComment(string& str, string comment)
}
}
bool is_section(const string& str, string& name)
bool eoState::is_section(const string& str, string& name)
{
string::size_type pos = str.find("\\section{");
string::size_type pos = str.find(_tag_section_so);
if (pos == string::npos)
return false;
//else
string::size_type end = str.find("}");
string::size_type end = str.find(_tag_section_sc);
if (end == string::npos)
return false;
// else
name = str.substr(pos + 9, end-9);
// affect name, passed by reference
// Note: substr( start, count )
name = str.substr( pos + _tag_section_so.size(), end - _tag_section_so.size() );
return true;
}
@ -84,6 +86,7 @@ void eoState::load(const string& _filename)
load(is);
}
// FIXME implement parsing and loading of other formats
void eoState::load(std::istream& is)
{
string str;
@ -158,16 +161,49 @@ void eoState::save(const string& filename) const
save(os);
}
void eoState::save(std::ostream& os) const
{ // saves in order of insertion
for (vector<ObjectMap::iterator>::const_iterator it = creationOrder.begin(); it != creationOrder.end(); ++it)
{
os << "\\section{" << (*it)->first << "}\n";
(*it)->second->printOn(os);
os << '\n';
}
//void eoState::save(std::ostream& os) const
//{ // saves in order of insertion
// for (vector<ObjectMap::iterator>::const_iterator it = creationOrder.begin(); it != creationOrder.end(); ++it)
// {
// os << "\\section{" << (*it)->first << "}\n";
// (*it)->second->printOn(os);
// os << '\n';
// }
//}
void eoState::saveSection( std::ostream& os, vector<ObjectMap::iterator>::const_iterator it) const
{
os << _tag_section_so << (*it)->first << _tag_section_sc;
os << _tag_content_s;
(*it)->second->printOn(os);
os << _tag_content_e;
os << _tag_section_e;
}
void eoState::save(std::ostream& os) const
{
os << _tag_state_so << _tag_state_name << _tag_state_sc;
// save the first section
assert( creationOrder.size() > 0 );
// saves in order of insertion
vector<ObjectMap::iterator>::const_iterator it = creationOrder.begin();
saveSection(os,it);
it++;
while( it != creationOrder.end() ) {
// add a separator only before [1,n] elements
os << _tag_section_sep;
saveSection(os, it);
it++;
}
os << _tag_state_e;
}
string eoState::createObjectName(eoObject* obj)
{
if (obj == 0)

View file

@ -31,6 +31,7 @@
#include <string>
#include <map>
#include <vector>
#include <assert.h>
#include <eoFunctorStore.h>
@ -56,10 +57,50 @@ class eoState : public eoFunctorStore
{
public :
eoState(void) {}
eoState(std::string name="") :
_tag_state_so(""),
_tag_state_name(name),
_tag_state_sc(""),
_tag_section_so("\\section{"),
_tag_section_sc("}\n"),
_tag_content_s(""),
_tag_content_e(""),
_tag_section_sep(""),
_tag_section_e("\n"),
_tag_state_e("")
{}
~eoState(void);
void formatLatex(std::string name)
{
_tag_state_so = "";
_tag_state_name = name;
_tag_state_sc = "";
_tag_section_so = "\\section{";
_tag_section_sc = "}\n";
_tag_content_s = "";
_tag_content_e = "";
_tag_section_sep = "";
_tag_section_e = "\n";
_tag_state_e = "";
}
void formatJSON(std::string name)
{
_tag_state_so = "{ \"";
_tag_state_name = name;
_tag_state_sc = "\":\n";
_tag_section_so = "\t{ \"";
_tag_section_sc = "\":\n";
_tag_content_s = "\"";
_tag_content_e = "\"";
_tag_section_sep = ",\n";
_tag_section_e = "\t}\n";
_tag_state_e = "}\n";
}
/**
* Object registration function, note that it does not take ownership!
*/
@ -131,6 +172,43 @@ private :
eoState(const eoState&);
eoState& operator=(const eoState&);
/* \@{
* s=start, e=end
* o=open, c=close
*
* { "my_state":
* {
* "section_pop":"",
* "section_rng":""
* }
* }
*
* // JSON LATEX (default)
*/
std::string _tag_state_so; // { "
std::string _tag_state_name; // my_state
std::string _tag_state_sc; // ":
std::string _tag_section_so; // { " \\section{
std::string _tag_section_sc; // ": }\n
std::string _tag_content_s; // "
std::string _tag_content_e; // "
std::string _tag_section_sep;// ,
std::string _tag_section_e; // } \n
std::string _tag_state_e; // }
/** \@} */
void removeComment( std::string& str, std::string comment);
bool is_section(const std::string& str, std::string& name);
protected:
void saveSection( std::ostream& os, std::vector<ObjectMap::iterator>::const_iterator it) const;
};
/** @example t-eoStateAndParser.cpp
*/

View file

@ -43,6 +43,7 @@ Authors:
class eoStdoutMonitor : public eoOStreamMonitor
{
public :
/* FIXME remove in next release
eoStdoutMonitor(bool _verbose, std::string _delim = "\t", unsigned int _width=20, char _fill=' ' ) :
eoOStreamMonitor( std::cout, _verbose, _delim, _width, _fill)
{
@ -50,6 +51,7 @@ public :
eo::log << eo::warnings << "WARNING: the use of the verbose parameter in eoStdoutMonitor constructor is deprecated and will be removed in the next release" << std::endl;
#endif // !DEPRECATED_MESSAGES
}
*/
eoStdoutMonitor(std::string _delim = "\t", unsigned int _width=20, char _fill=' ' ) :
eoOStreamMonitor( std::cout, _delim, _width, _fill)

329
eo/src/utils/eoTimer.h Normal file
View file

@ -0,0 +1,329 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
# ifndef __EO_TIMER_H__
# define __EO_TIMER_H__
# include <sys/time.h> // time()
# include <sys/resource.h> // rusage()
# include <vector> // std::vector
# include <map> // std::map
# include "utils/eoParallel.h" // eo::parallel
# include "serial/eoSerial.h" // eo::Persistent
/**
* @brief Timer allowing to measure time between a start point and a stop point.
*
* This timer allows the user to measure user time, system time and wallclock time
* between two points. Basically, user time is time spent in developer code ; system
* time is time spent during the IO wait and system calls ; wallclock is the difference
* of time we could observe by measuring time with a watch.
*
* @ingroup Utilities
*/
class eoTimer
{
public:
/**
* @brief Default ctor. Begins all the timers.
*/
eoTimer()
{
uuremainder = 0;
usremainder = 0;
restart();
}
/**
* @brief Restarts all the timers and launch the measure.
*/
void restart()
{
wc_start = time(NULL);
getrusage( RUSAGE_SELF, &_start );
}
/**
* @brief Measures the user time spent since the last restart().
*
* If the number of elapsed seconds is zero, the spent milliseconds are
* added to a remainder. If the remainder exceeds one second, it is
* added to the number of elapsed seconds.
*
* @return Number of seconds elapsed in user space.
*/
long int usertime()
{
struct rusage _now;
getrusage( RUSAGE_SELF, &_now );
long int result = _now.ru_utime.tv_sec - _start.ru_utime.tv_sec;
long int remainder = _now.ru_utime.tv_usec - _start.ru_utime.tv_usec;
if( remainder >= 0 )
{
uuremainder += remainder;
} else
{
uuremainder += ( 1000000 - remainder );
--result;
}
if( uuremainder >= 1000000 )
{
uuremainder -= 1000000;
++result;
}
return result;
}
/**
* @brief Measures the system time spent since the last restart().
*
* If the number of elapsed seconds is zero, the spent milliseconds are
* added to a remainder. If the remainder exceeds one second, it is
* added to the number of elapsed seconds.
*
* @return Number of seconds elapsed in system (kernel) space.
*/
long int systime()
{
struct rusage _now;
getrusage( RUSAGE_SELF, &_now );
long int result = _now.ru_stime.tv_sec - _start.ru_stime.tv_sec;
long int remainder = _now.ru_stime.tv_usec - _start.ru_stime.tv_usec;
if( remainder >= 0 )
{
usremainder += remainder;
} else
{
usremainder += ( 1000000 - remainder );
--result;
}
if( usremainder >= 1000000 )
{
usremainder -= 1000000;
++result;
}
return result;
}
/**
* @brief Measures the wallclock time spent since the last restart().
*
* @return Number of seconds elapsed, as a double.
*/
double wallclock()
{
return std::difftime( std::time(NULL) , wc_start );
}
protected:
// Structure used to measure user and system time.
struct rusage _start;
// Remainder (in milliseconds) for user time.
long int uuremainder;
// Remainder (in milliseconds) for system time.
long int usremainder;
// Structure used to measure wallclock time.
time_t wc_start;
};
/**
* @brief Registers a group of statistics, each statistic corresponding to user, system and wallclock times distribution.
*
* This class helps the user to measure time in different parts of an application. A name is associated to a statistic,
* on each call to start() and stop() for this name, a new number is added to the statistic, for each of the three
* measured times.
*
* The statistics are only registered if the option "--parallelized-do-measure" is set to true, which can be checked
* thanks to global object eo::parallel.
*
* This shows how the eoTimerStat can be used :
* @code
* eoTimerStat timerStat;
* timerStat.start("first_point");
* for( int i = 0; i < 1000; ++i )
* {
* timerStat.start("single_computation");
* single_computation( i );
* timerStat.stop("single_computation");
* }
* // After this loop, timerStat contains a statistic of key "single_computation" which contains 1000 measures for
* // each type of time.
* timerStat.stop("first_point");
* // After this line, timerStat contains another statistic of key "first_point" which counted the duration of the
* // whole loop.
*
* int singleComputationUsertimeMean = 0;
* for( int i = 0; i < 1000; ++i )
* {
* singleComputationUsertimeMean += timerStat.stats()["single_computation"].utime[i];
* }
* std::cout << "Mean of user time spent in single computation: " << singleComputationUsertimeMean / 1000. << std::endl;
* @endcode
*
* When using MPI, these statistics can be readily be serialized, so as to be sent over a network, for instance.
*
* Implementation details: this eoTimerStat is in fact a map of strings (key) / Stat (value). Stat is an internal
* structure directly defined in the class, which contains three vectors modeling the distributions of the different
* types of elapsed times. Another map of strings (key) / eoTimer (value) allows to effectively retrieve the different
* times. The struct Stat will be exposed to client, which will use its members ; however,
* the client doesn't have anything to do directly with the timer, that's why the two maps are splitted.
*
* @ingroup Utilities
*/
class eoTimerStat
# ifdef WITH_MPI
: public eoserial::Persistent
# endif
{
public:
/**
* @brief Statistic related to a key (name).
*
* This structure is the value in the map saved in the eoTimerStat. It contains the statistic bound to a key,
* which are the user time distribution, the system time distribution and the wallclock time distribution, as
* std::vector s.
*
* It can readily be serialized with boost when compiling with mpi.
*/
struct Stat
# ifdef WITH_MPI
: public eoserial::Persistent
# endif
{
std::vector<long int> utime;
std::vector<long int> stime;
std::vector<double> wtime;
#ifdef WITH_MPI
void unpack( const eoserial::Object* obj )
{
utime.clear();
static_cast< eoserial::Array* >(obj->find("utime")->second)
->deserialize< std::vector<long int>, eoserial::Array::UnpackAlgorithm >( utime );
stime.clear();
static_cast< eoserial::Array* >(obj->find("stime")->second)
->deserialize< std::vector<long int>, eoserial::Array::UnpackAlgorithm >( stime );
wtime.clear();
static_cast< eoserial::Array* >(obj->find("wtime")->second)
->deserialize< std::vector<double>, eoserial::Array::UnpackAlgorithm >( wtime );
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add("utime", eoserial::makeArray< std::vector<long int>, eoserial::MakeAlgorithm >( utime ) );
obj->add("stime", eoserial::makeArray< std::vector<long int>, eoserial::MakeAlgorithm >( stime ) );
obj->add("wtime", eoserial::makeArray< std::vector<double>, eoserial::MakeAlgorithm >( wtime ) );
return obj;
}
# endif
};
#ifdef WITH_MPI
void unpack( const eoserial::Object* obj )
{
_stats.clear();
for( eoserial::Object::const_iterator it = obj->begin(), final = obj->end();
it != final;
++it)
{
eoserial::unpackObject( *obj, it->first, _stats[ it->first ] );
}
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
for( std::map<std::string, Stat >::const_iterator it = _stats.begin(), final = _stats.end();
it != final;
++it)
{
obj->add( it->first, it->second.pack() );
}
return obj;
}
# endif
/**
* @brief Starts a new measure for the given key.
*
* This is only performed if parallel.doMeasure() is true, which is equivalent to the fact that
* parser found "--parallel-do-measure=1" in command line args.
*
* @param key The key of the statistic.
*/
void start( const std::string & key )
{
if( eo::parallel.doMeasure() )
{
_timers[ key ].restart();
}
}
/**
* @brief Stops the mesure for the given key and saves the elapsed times.
*
* Must follow a call of start with the same key.
*
* This is only performed if parallel.doMeasure() is true, which is equivalent to the fact that
* parser found "--parallel-do-measure=1" in command line args.
*
* @param key The key of the statistic.
*/
void stop( const std::string& key )
{
if( eo::parallel.doMeasure() )
{
Stat & s = _stats[ key ];
eoTimer & t = _timers[ key ];
s.utime.push_back( t.usertime() );
s.stime.push_back( t.systime() );
s.wtime.push_back( t.wallclock() );
}
}
/**
* @brief Getter for the statistics map.
*/
std::map< std::string, Stat >& stats()
{
return _stats;
}
protected:
// Statistics map: links a key (string) to a statistic.
std::map< std::string, Stat > _stats;
// Timers map: links a key to its timer.
std::map< std::string, eoTimer > _timers;
};
# endif // __TIMER_H__

View file

@ -9,22 +9,22 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/contrib)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/contrib/MGE)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${EO_SRC_DIR}/src)
include_directories(${EO_SRC_DIR}/contrib)
include_directories(${EO_SRC_DIR}/contrib/MGE)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
link_directories(${EO_BIN_DIR}/lib)
######################################################################################
### 3) Define your targets and link the librairies
######################################################################################
SET (TEST_LIST
set (TEST_LIST
t-eofitness
t-eoRandom
t-eobin
@ -72,45 +72,45 @@ SET (TEST_LIST
)
FOREACH (test ${TEST_LIST})
SET ("T_${test}_SOURCES" "${test}.cpp")
ENDFOREACH (test)
foreach (test ${TEST_LIST})
set ("T_${test}_SOURCES" "${test}.cpp")
endforeach (test)
IF(ENABLE_MINIMAL_CMAKE_TESTING)
if(ENABLE_MINIMAL_CMAKE_TESTING)
SET (MIN_TEST_LIST t-eoEasyPSO)
FOREACH (mintest ${MIN_TEST_LIST})
SET ("T_${mintest}_SOURCES" "${mintest}.cpp")
ADD_EXECUTABLE(${mintest} ${T_${mintest}_SOURCES})
ADD_TEST(${mintest} ${mintest})
TARGET_LINK_LIBRARIES(${mintest} ga es cma eoutils eo)
ENDFOREACH (mintest)
set (MIN_TEST_LIST t-eoEasyPSO)
foreach (mintest ${MIN_TEST_LIST})
set ("T_${mintest}_SOURCES" "${mintest}.cpp")
add_executable(${mintest} ${T_${mintest}_SOURCES})
add_test(${mintest} ${mintest})
target_link_libraries(${mintest} ga es cma eoutils eo)
endforeach (mintest)
ELSEIF(ENABLE_CMAKE_TESTING)
elseif(ENABLE_CMAKE_TESTING)
FOREACH (test ${TEST_LIST})
ADD_EXECUTABLE(${test} ${T_${test}_SOURCES})
ADD_TEST(${test} ${test})
TARGET_LINK_LIBRARIES(${test} ga es cma eoutils eo)
INSTALL(TARGETS ${test} RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/test COMPONENT test)
ENDFOREACH (test)
foreach (test ${TEST_LIST})
add_executable(${test} ${T_${test}_SOURCES})
add_test(${test} ${test})
target_link_libraries(${test} ga es cma eoutils eo)
install(TARGETS ${test} RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/test COMPONENT test)
endforeach (test)
SET(RESOURCES
set(RESOURCES
boxplot.py
boxplot_to_png.py
boxplot_to_pdf.py
t-openmp.py
)
FOREACH(file ${RESOURCES})
EXECUTE_PROCESS(
foreach(file ${RESOURCES})
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/${file}
${CMAKE_CURRENT_BINARY_DIR}/${file}
)
ENDFOREACH(file)
endforeach(file)
ENDIF(ENABLE_MINIMAL_CMAKE_TESTING)
endif(ENABLE_MINIMAL_CMAKE_TESTING)
######################################################################################

View file

@ -0,0 +1,54 @@
###############################################################################
##
## CMakeLists file for eo/test/mpi
##
###############################################################################
######################################################################################
### 1) Include the sources
######################################################################################
message("EO SOURCE DIR: ${EO_SRC_DIR}")
message("OMPI: ${MPI_DIR}")
include_directories(${MPI_DIR}/include)
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
link_directories(${EO_BIN_DIR}/lib)
link_directories(${MPI_DIR}/lib)
######################################################################################
### 3) Define your targets and link the librairies
######################################################################################
set (TEST_LIST
t-mpi-parallelApply
t-mpi-wrapper
t-mpi-multipleRoles
t-mpi-eval
t-mpi-multistart
t-mpi-distrib-exp
)
foreach (test ${TEST_LIST})
set ("T_${test}_SOURCES" "${test}.cpp")
endforeach (test)
set(CMAKE_CXX_COMPILER "mpicxx")
add_definitions(-DWITH_MPI)
if(ENABLE_CMAKE_TESTING)
foreach (test ${TEST_LIST})
add_executable(${test} ${T_${test}_SOURCES})
add_test(${test} ${test})
target_link_libraries(${test} eoutils eompi eoserial eo)
install(TARGETS ${test} RUNTIME DESTINATION share/eo/test COMPONENT test)
endforeach (test)
endif()
######################################################################################

View file

@ -0,0 +1,51 @@
# ifndef __T_MPI_COMMON_H__
# define __T_MPI_COMMON_H__
#include <serial/eoSerial.h>
/**
* @file t-mpi-common.h
*
* This file shows an example of serialization of a primitive type, so as to be used in a parallel algorithm.
* It is fully compatible with the basic type, by implementing conversion operator and constructor based on type.
* It can contain any simple type which can be written in a std::ostream.
*/
template< class T >
struct SerializableBase : public eoserial::Persistent
{
public:
operator T&()
{
return _value;
}
SerializableBase() : _value()
{
// empty
}
SerializableBase( T base ) : _value( base )
{
// empty
}
void unpack( const eoserial::Object* obj )
{
eoserial::unpack( *obj, "value", _value );
}
eoserial::Object* pack(void) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add("value", eoserial::make( _value ) );
return obj;
}
private:
T _value;
};
# endif // __T_MPI_COMMON_H__

View file

@ -0,0 +1,135 @@
# include <unistd.h> // usleep
# include <iostream>
# include <string>
# include <vector>
# include <eo>
# include <mpi/eoParallelApply.h>
# include "../test/mpi/t-mpi-common.h"
using namespace eo::mpi;
typedef SerializableBase<int> type;
struct Wait : public eoUF< type &, void >
{
void operator()( type & milliseconds )
{
std::cout << "Sleeping for " << milliseconds << "ms..." << std::endl;
// usleep takes an input in microseconds
usleep( milliseconds * 1000 );
}
} wait;
class Distribution : public std::vector< type >
{
public:
/**
* @brief Really fills the vector with the distribution values.
*/
void fill( unsigned size )
{
for( unsigned i = 0; i < size; ++i )
{
push_back( next_element() );
}
}
/**
* @brief Returns the next element of the distribution to put in the
* vector.
*
* @returns Number of milliseconds to wait
*/
virtual int next_element() = 0;
// Idea for function name: enlarge_your_parser
/**
* @brief Creates params and retrieves values from parser
*/
virtual void make_parser( eoParser & parser ) = 0;
/**
* @brief Returns true if this distribution has been activated by the
* command line.
*
* Serves to main program to check if at least one distribution has been
* activated.
*/
bool isActive() { return _active; }
protected:
bool _active;
};
class UniformDistribution : public Distribution
{
public:
UniformDistribution() : _rng(0)
{
// empty
}
void make_parser( eoParser & parser )
{
_active = parser.createParam( false, "uniform", "Uniform distribution", '\0', "Uniform").value();
_min = parser.createParam( 0.0, "uniform-min", "Minimum for uniform distribution", '\0', "Uniform").value();
_max = parser.createParam( 1.0, "uniform-max", "Maximum for uniform distribution", '\0', "Uniform").value();
}
int next_element()
{
return std::floor( 1000. * _rng.uniform( _min, _max ) );
}
protected:
eoRng _rng;
double _min;
double _max;
} uniformDistribution;
int main( int argc, char** argv )
{
Node::init( argc, argv );
eoParser parser( argc, argv );
// TODO for each available distribution, check if activated.
// If no distribution is activated, show an error message
// If two distributions or more are activated, show an error message
// Otherwise, use the activated distribution as distrib
Distribution & distrib = uniformDistribution;
// Make parser of distribution here
distrib.make_parser( parser );
unsigned size = parser.createParam( 10U, "size", "Number of elements to distribute.", 's', "Distribution").value();
unsigned packet_size = parser.createParam( 1U, "packet_size", "Number of elements to distribute at each time for a single worker.", 'p', "Parallelization").value();
make_parallel( parser );
make_help( parser );
ParallelApplyStore< type> store( wait, DEFAULT_MASTER, packet_size );
// Fill distribution
distrib.fill( size );
store.data( distrib );
DynamicAssignmentAlgorithm scheduling;
ParallelApply< type > job( scheduling, DEFAULT_MASTER, store );
job.run();
if( job.isMaster() )
{
EmptyJob( scheduling, DEFAULT_MASTER ); // to terminate parallel apply
}
return 0;
}

206
eo/test/mpi/t-mpi-eval.cpp Normal file
View file

@ -0,0 +1,206 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of parallel evaluation of a population, when using an eoEasyEA algorithm.
* Moreover, we add a basic wrapper on the parallel evaluation, so as to show how to retrieve the best solutions.
*/
//-----------------------------------------------------------------------------
#include <eo>
#include <eoPopEvalFunc.h>
#include <es/make_real.h>
#include "../real_value.h"
#include <mpi/eoMpi.h>
#include <vector>
using namespace std;
//-----------------------------------------------------------------------------
class eoRealSerializable : public eoReal< eoMinimizingFitness >, public eoserial::Persistent
{
public:
eoRealSerializable(unsigned size = 0, double value = 0.0):
eoReal<eoMinimizingFitness>(size, value) {}
eoserial::Object* pack() const
{
eoserial::Object* obj = new eoserial::Object;
obj->add( "array",
eoserial::makeArray< vector<double>, eoserial::MakeAlgorithm >
( *this )
);
bool invalidFitness = invalid();
obj->add("invalid", eoserial::make( invalidFitness ) );
if( !invalidFitness )
{
double fitnessVal = fitness();
obj->add("fitness", eoserial::make( fitnessVal ) );
}
return obj;
}
void unpack( const eoserial::Object* obj )
{
this->clear();
eoserial::unpackArray< vector<double>, eoserial::Array::UnpackAlgorithm >
( *obj, "array", *this );
bool invalidFitness;
eoserial::unpack( *obj, "invalid", invalidFitness );
if( invalidFitness ) {
invalidate();
} else {
double fitnessVal;
eoserial::unpack<double>( *obj, "fitness", fitnessVal );
fitness( fitnessVal );
}
}
};
typedef eoRealSerializable EOT;
/*
* Wrapper for HandleResponse: shows the best answer, as it is found.
*
* Finding the best solution is an associative operation (as it is based on a "min" function, which is associative too)
* and that's why we can perform it here. Indeed, the min element of 5 elements is the min element of the 3 first
* elements and the min element of the 2 last elements:
* min(1, 2, 3, 4, 5) = min( min(1, 2, 3), min(4, 5) )
*
* This is a reduction. See MapReduce example to have another examples of reduction.
*/
struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply<EOT>
{
CatBestAnswers()
{
best.fitness( 1000000000. );
}
/*
our structure inherits the member _wrapped from HandleResponseFunction,
which is a HandleResponseFunction pointer;
it inherits also the member _d (like Data), which is a pointer to the
ParallelApplyData used in the HandleResponseParallelApply&lt;EOT&gt;. Details
of this data are contained in the file eoParallelApply. We need just to know that
it contains a member assignedTasks which maps a worker rank and the sent slice
to be processed by the worker, and a reference to the processed table via the
call of the data() function.
*/
// if EOT were a template, we would have to do: (thank you C++ :)
// using eo::mpi::HandleResponseParallelApply<EOT>::_wrapped;
// using eo::mpi::HandleResponseParallelApply<EOT>::d;
void operator()(int wrkRank)
{
eo::mpi::ParallelApplyData<EOT> * d = _data;
// Retrieve informations about the slice processed by the worker
int index = d->assignedTasks[wrkRank].index;
int size = d->assignedTasks[wrkRank].size;
// call to the wrapped function HERE
(*_wrapped)( wrkRank );
// Compare fitnesses of evaluated individuals with the best saved
for(int i = index; i < index+size; ++i)
{
if( best.fitness() < d->table()[ i ].fitness() )
{
eo::log << eo::quiet << "Better solution found:" << d->table()[i].fitness() << std::endl;
best = d->table()[ i ];
}
}
}
protected:
EOT best;
};
int main(int ac, char** av)
{
eo::mpi::Node::init( ac, av );
// eo::log << eo::setlevel( eo::debug );
eo::log << eo::setlevel( eo::quiet );
eoParser parser(ac, av);
unsigned int popSize = parser.getORcreateParam((unsigned int)100, "popSize", "Population Size", 'P', "Evolution Engine").value();
unsigned int dimSize = parser.getORcreateParam((unsigned int)10, "dimSize", "Dimension Size", 'd', "Evolution Engine").value();
uint32_t seedParam = parser.getORcreateParam((uint32_t)0, "seed", "Random number seed", 0).value();
if (seedParam == 0) { seedParam = time(0); }
make_parallel(parser);
make_help(parser);
rng.reseed( seedParam );
eoUniformGenerator< double > gen(-5, 5);
eoInitFixedLength< EOT > init( dimSize, gen );
eoEvalFuncPtr< EOT, double, const std::vector< double >& > mainEval( real_value );
eoEvalFuncCounter< EOT > eval( mainEval );
// until this point, everything (but eo::mpi::Node::init) is exactly as in an sequential version.
// We then instanciate the parallel algorithm. The store is directly used by the eoParallelPopLoopEval, which
// internally uses parallel apply.
int rank = eo::mpi::Node::comm().rank();
eo::mpi::DynamicAssignmentAlgorithm assign;
if( rank == eo::mpi::DEFAULT_MASTER )
{
eoPop< EOT > pop( popSize, init );
eo::log << "Size of population : " << popSize << std::endl;
eo::mpi::ParallelApplyStore< EOT > store( eval, eo::mpi::DEFAULT_MASTER );
store.wrapHandleResponse( new CatBestAnswers );
eoParallelPopLoopEval< EOT > popEval( assign, eo::mpi::DEFAULT_MASTER, &store );
//eoParallelPopLoopEval< EOT > popEval( assign, eo::mpi::DEFAULT_MASTER, eval, 5 );
eo::log << eo::quiet << "Before first evaluation." << std::endl;
popEval( pop, pop );
eo::log << eo::quiet << "After first evaluation." << std::endl;
pop = eoPop< EOT >( popSize, init );
popEval( pop, pop );
eo::log << eo::quiet << "After second evaluation." << std::endl;
eo::log << eo::quiet << "DONE!" << std::endl;
} else
{
eoPop< EOT > pop; // the population doesn't have to be initialized, as it is not used by workers.
eoParallelPopLoopEval< EOT > popEval( assign, eo::mpi::DEFAULT_MASTER, eval );
popEval( pop, pop );
}
return 0;
}
//-----------------------------------------------------------------------------

View file

@ -0,0 +1,196 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of how to make a hierarchy between nodes, when using a parallel apply. In this basic
* test, the master delegates the charge of finding workers to 2 "sub" masters, which then send part of the table to
* their workers.
*
* It's convenient to establish a role map, so as to clearly identify every role:
* - The node 0 is the general master, that delegates the job. It sends the table to the 2 submasters, and waits for the
* results.
* - Nodes 1 and 2 are the worker of the first job: the delegates. They receive the elements of the table and
* retransmit them to the subworkers. They play the roles of worker in the delegating job, and master in the plus one
* job.
* - Following nodes (3 to 6) are workers of the plus one job. They do the real job. Nodes 3 and 5 are attached to
* submaster 1, 4 and 6 to submaster 2.
*
* This test requires exactly 7 hosts. If the size is bigger, an exception will be thrown at the beginning.
**/
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include "t-mpi-common.h"
# include <iostream>
# include <vector>
using namespace std;
using namespace eo::mpi;
/*
* This class allows the user to easily serialize a vector of elements which implement eoserial::Persistent too.
*
* T is the type of the contained element, which must implement eoserial::Persistent too.
*
* Here, it contains SerializableBase<int>, which is a serializable integer that can be used as an integer.
*/
template< class T >
struct SerializableVector : public std::vector<T>, public eoserial::Persistent
{
public:
void unpack( const eoserial::Object* obj )
{
this->clear();
eoserial::Array* vector = static_cast<eoserial::Array*>( obj->find("vector")->second );
vector->deserialize< std::vector<T>, eoserial::Array::UnpackObjectAlgorithm >( *this );
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add("vector", eoserial::makeArray< std::vector<T>, eoserial::SerializablePushAlgorithm >( *this ) );
return obj;
}
};
// The real job to execute, for the subworkers: add one to each element of a table.
struct SubWork: public eoUF< SerializableBase<int>&, void >
{
void operator() ( SerializableBase<int> & x )
{
cout << "Subwork phase." << endl;
++x;
}
};
// Function called by both subworkers and delegates.
// v is the vector to process, rank is the MPI rank of the sub master
void subtask( vector< SerializableBase<int> >& v, int rank )
{
// Attach workers according to nodes.
// Submaster with rank 1 will have ranks 3 and 5 as subworkers.
// Submaster with rank 2 will have ranks 4 and 6 as subworkers.
vector<int> workers;
workers.push_back( rank + 2 );
workers.push_back( rank + 4 );
DynamicAssignmentAlgorithm algo( workers );
SubWork sw;
// Launch the job!
ParallelApplyStore< SerializableBase<int> > store( sw, rank );
store.data( v );
ParallelApply< SerializableBase<int> > job( algo, rank, store );
job.run();
EmptyJob stop( algo, rank );
}
// Functor applied by submasters. Wait for the subworkers responses and then add some random processing (here, multiply
// each result by two).
// Note that this work receives a vector of integers as an entry, while subworkers task's operator receives a simple
// integer.
struct Work: public eoUF< SerializableVector< SerializableBase<int> >&, void >
{
void operator() ( SerializableVector< SerializableBase<int> >& v )
{
cout << "Work phase..." << endl;
subtask( v, Node::comm().rank() );
for( unsigned i = 0; i < v.size(); ++i )
{
v[i] *= 2;
}
}
};
int main(int argc, char** argv)
{
// eo::log << eo::setlevel( eo::debug );
Node::init( argc, argv );
if( Node::comm().size() != 7 ) {
throw std::runtime_error("World size should be 7.");
}
SerializableVector< SerializableBase<int> > v;
v.push_back(1);
v.push_back(3);
v.push_back(3);
v.push_back(7);
v.push_back(42);
// As submasters' operator receives a vector<int> as an input, and ParallelApply takes a vector of
// operator's input as an input, we have to deal with a vector of vector of integers for the master task.
vector< SerializableVector< SerializableBase<int> > > metaV;
// Here, we send twice the same vector. We could also have splitted the first vector into two vectors, one
// containing the beginning and another one containing the end.
metaV.push_back( v );
metaV.push_back( v );
// Assigning roles is done by comparing MPI ranks.
switch( Node::comm().rank() )
{
// Nodes from 0 to 2 are implicated into the delegating task.
case 0:
case 1:
case 2:
{
Work w;
DynamicAssignmentAlgorithm algo( 1, 2 );
ParallelApplyStore< SerializableVector< SerializableBase<int> > > store( w, 0 );
store.data( metaV );
ParallelApply< SerializableVector< SerializableBase<int> > > job( algo, 0, store );
job.run();
if( job.isMaster() )
{
EmptyJob stop( algo, 0 );
v = metaV[0];
cout << "Results : " << endl;
for(unsigned i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
}
}
break;
// Other nodes are implicated into the subwork task.
default:
{
// all the other nodes are sub workers
int rank = Node::comm().rank();
if ( rank == 3 or rank == 5 )
{
subtask( v, 1 );
} else {
subtask( v, 2 );
}
}
break;
}
return 0;
}

View file

@ -0,0 +1,169 @@
# include <mpi/eoMultiStart.h>
using namespace eo::mpi;
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <eo>
#include <es.h>
/*
* This file is based on the tutorial lesson 1. We'll consider that you know all the EO
* related parts of the algorithm and we'll focus our attention on parallelization.
*
* This file shows an example of multistart applied to a eoSGA (simple genetic
* algorithm). As individuals need to be serialized, we implement a class inheriting
* from eoReal (which is the base individual), so as to manipulate individuals as they
* were eoReal AND serialize them.
*
* The main function shows how to launch a multistart job, with default functors. If you
* don't know which functors to use, these ones should fit the most of your purposes.
*/
using namespace std;
/*
* eoReal is a vector of double: we just have to serializes the value and the fitness.
*/
class SerializableEOReal: public eoReal<double>, public eoserial::Persistent
{
public:
SerializableEOReal(unsigned size = 0, double value = 0.0) :
eoReal<double>(size, value)
{
// empty
}
void unpack( const eoserial::Object* obj )
{
this->clear();
eoserial::unpackArray
< std::vector<double>, eoserial::Array::UnpackAlgorithm >
( *obj, "vector", *this );
bool invalidFitness;
eoserial::unpack( *obj, "invalid_fitness", invalidFitness );
if( invalidFitness )
{
this->invalidate();
} else
{
double f;
eoserial::unpack( *obj, "fitness", f );
this->fitness( f );
}
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add( "vector", eoserial::makeArray< std::vector<double>, eoserial::MakeAlgorithm >( *this ) );
bool invalidFitness = this->invalid();
obj->add( "invalid_fitness", eoserial::make( invalidFitness ) );
if( !invalidFitness )
{
obj->add( "fitness", eoserial::make( this->fitness() ) );
}
return obj;
}
};
// REPRESENTATION
//-----------------------------------------------------------------------------
// define your individuals
typedef SerializableEOReal Indi;
// EVAL
//-----------------------------------------------------------------------------
// a simple fitness function that computes the euclidian norm of a real vector
// @param _indi A real-valued individual
double real_value(const Indi & _indi)
{
double sum = 0;
for (unsigned i = 0; i < _indi.size(); i++)
sum += _indi[i]*_indi[i];
return (-sum); // maximizing only
}
/************************** PARALLELIZATION JOB *******************************/
int main(int argc, char **argv)
{
Node::init( argc, argv );
// PARAMETRES
// all parameters are hard-coded!
const unsigned int SEED = 133742; // seed for random number generator
const unsigned int VEC_SIZE = 8; // Number of object variables in genotypes
const unsigned int POP_SIZE = 100; // Size of population
const unsigned int T_SIZE = 3; // size for tournament selection
const unsigned int MAX_GEN = 100; // Maximum number of generation before STOP
const float CROSS_RATE = 0.8; // Crossover rate
const double EPSILON = 0.01; // range for real uniform mutation
const float MUT_RATE = 0.5; // mutation rate
eoEvalFuncPtr<Indi> eval( real_value );
eoPop<Indi> pop;
eoUniformGenerator< double > generator;
eoInitFixedLength< Indi > init( VEC_SIZE, generator );
pop = eoPop<Indi>( POP_SIZE, init );
eoDetTournamentSelect<Indi> select(T_SIZE);
eoSegmentCrossover<Indi> xover;
eoUniformMutation<Indi> mutation(EPSILON);
eoGenContinue<Indi> continuator(MAX_GEN);
/* Does work too with a steady fit continuator. */
// eoSteadyFitContinue< Indi > continuator( 10, 50 );
eoSGA<Indi> gga(select, xover, CROSS_RATE, mutation, MUT_RATE,
eval, continuator);
/* How to assign tasks, which are starts? */
DynamicAssignmentAlgorithm assignmentAlgo;
/* Before a worker starts its algorithm, how does it reinits the population?
* There are a few default usable functors, defined in eoMultiStart.h.
*
* This one (ReuseSamePopEA) doesn't modify the population after a start, so
* the same population is reevaluated on each multistart: the solution tend
* to get better and better.
*/
ReuseSamePopEA< Indi > resetAlgo( continuator, pop, eval );
/**
* How to send seeds to the workers, at the beginning of the parallel job?
* This functors indicates that seeds should be random values.
*/
GetRandomSeeds< Indi > getSeeds( SEED );
// Builds the store
MultiStartStore< Indi > store(
gga,
DEFAULT_MASTER,
resetAlgo,
getSeeds);
// Creates the multistart job and runs it.
// The last argument indicates that we want to launch 5 runs.
MultiStart< Indi > msjob( assignmentAlgo, DEFAULT_MASTER, store, 5 );
msjob.run();
if( msjob.isMaster() )
{
msjob.best_individuals().sort();
std::cout << "Global best individual has fitness " << msjob.best_individuals().best_element().fitness() << std::endl;
}
MultiStart< Indi > msjob10( assignmentAlgo, DEFAULT_MASTER, store, 10 );
msjob10.run();
if( msjob10.isMaster() )
{
msjob10.best_individuals().sort();
std::cout << "Global best individual has fitness " << msjob10.best_individuals().best_element().fitness() << std::endl;
}
return 0;
}

View file

@ -0,0 +1,220 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of use of parallel apply, in the following context: each element of a table is
* incremented... in a parallel fashion. While this operation is very easy to perform even on a single host, it's just
* an example for parallel apply use.
*
* The table of integers has to be serialized before it's sent. The wrapper object SerializableBase allows to serialize
* any type and manipulate it like this type: SerializableBase<int> can be exactly be used as an integer.
*
* Besides, this is also a test for assignment (scheduling) algorithms, in different cases. The test succeeds if and
* only if the program terminates without any segfault ; otherwise, there could be a deadlock which prevents the end or
* a segfault at any time.
*
* One important thing is to instanciate an EmptyJob after having launched a ParallelApplyJob, so as the workers to be
* aware that the job is done (as it's a MultiJob).
*
* This test needs at least 3 processes to be launched. Under this size, it will directly throw an exception, at the
* beginning;
*/
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include "t-mpi-common.h"
# include <iostream>
# include <cstdlib>
# include <vector>
using namespace std;
using namespace eo::mpi;
/*
* The function to be called on each element of the table: just increment the value.
*/
struct plusOne : public eoUF< SerializableBase<int>&, void >
{
void operator() ( SerializableBase<int> & x )
{
++x; // implicit conversion of SerializableBase<int> in the integer it contains
}
};
/*
* Internal structure representating a test.
*/
struct Test
{
AssignmentAlgorithm * assign; // used assignment algorithm for this test.
string description; // textual description of the test
int requiredNodesNumber; // number of required nodes. NB : chosen nodes ranks must be sequential
};
int main(int argc, char** argv)
{
// eo::log << eo::setlevel( eo::debug ); // if you like tty full of rainbows, decomment this line and comment the following one.
eo::log << eo::setlevel( eo::quiet );
bool launchOnlyOne = false ; // Set this to true if you wanna launch only the first test.
Node::init( argc, argv );
// Initializes a vector with random values.
srand( time(0) );
vector< SerializableBase<int> > v;
for( int i = 0; i < 1000; ++i )
{
v.push_back( rand() );
}
// We need to be sure the values are correctly incremented between each test. So as to check this, we save the
// original vector into a variable originalV, and put an offset variable to 0. After each test, the offset is
// incremented and we can compare the returned value of each element to the value of each element in originalV +
// offset. If the two values are different, there has been a problem.
int offset = 0;
vector< SerializableBase<int> > originalV = v;
// Instanciates the functor to apply on each element
plusOne plusOneInstance;
vector< Test > tests;
const int ALL = Node::comm().size();
if( ALL < 3 ) {
throw std::runtime_error("Needs at least 3 processes to be launched!");
}
// Tests are auto described thanks to member "description"
Test tIntervalStatic;
tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, REST_OF_THE_WORLD, v.size() );
tIntervalStatic.description = "Correct static assignment with interval."; // workers have ranks from 1 to size - 1
tIntervalStatic.requiredNodesNumber = ALL;
tests.push_back( tIntervalStatic );
if( !launchOnlyOne )
{
Test tWorldStatic;
tWorldStatic.assign = new StaticAssignmentAlgorithm( v.size() );
tWorldStatic.description = "Correct static assignment with whole world as workers.";
tWorldStatic.requiredNodesNumber = ALL;
tests.push_back( tWorldStatic );
Test tStaticOverload;
tStaticOverload.assign = new StaticAssignmentAlgorithm( v.size()+100 );
tStaticOverload.description = "Static assignment with too many runs.";
tStaticOverload.requiredNodesNumber = ALL;
tests.push_back( tStaticOverload );
Test tUniqueStatic;
tUniqueStatic.assign = new StaticAssignmentAlgorithm( 1, v.size() );
tUniqueStatic.description = "Correct static assignment with unique worker.";
tUniqueStatic.requiredNodesNumber = 2;
tests.push_back( tUniqueStatic );
Test tVectorStatic;
vector<int> workers;
workers.push_back( 1 );
workers.push_back( 2 );
tVectorStatic.assign = new StaticAssignmentAlgorithm( workers, v.size() );
tVectorStatic.description = "Correct static assignment with precise workers specified.";
tVectorStatic.requiredNodesNumber = 3;
tests.push_back( tVectorStatic );
Test tIntervalDynamic;
tIntervalDynamic.assign = new DynamicAssignmentAlgorithm( 1, REST_OF_THE_WORLD );
tIntervalDynamic.description = "Dynamic assignment with interval.";
tIntervalDynamic.requiredNodesNumber = ALL;
tests.push_back( tIntervalDynamic );
Test tUniqueDynamic;
tUniqueDynamic.assign = new DynamicAssignmentAlgorithm( 1 );
tUniqueDynamic.description = "Dynamic assignment with unique worker.";
tUniqueDynamic.requiredNodesNumber = 2;
tests.push_back( tUniqueDynamic );
Test tVectorDynamic;
tVectorDynamic.assign = new DynamicAssignmentAlgorithm( workers );
tVectorDynamic.description = "Dynamic assignment with precise workers specified.";
tVectorDynamic.requiredNodesNumber = tVectorStatic.requiredNodesNumber;
tests.push_back( tVectorDynamic );
Test tWorldDynamic;
tWorldDynamic.assign = new DynamicAssignmentAlgorithm;
tWorldDynamic.description = "Dynamic assignment with whole world as workers.";
tWorldDynamic.requiredNodesNumber = ALL;
tests.push_back( tWorldDynamic );
}
for( unsigned int i = 0; i < tests.size(); ++i )
{
// Instanciates a store with the functor, the master rank and size of packet (see ParallelApplyStore doc).
ParallelApplyStore< SerializableBase<int> > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 3 );
// Updates the contained data
store.data( v );
// Creates the job with the assignment algorithm, the master rank and the store
ParallelApply< SerializableBase<int> > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store );
// Only master writes information
if( job.isMaster() )
{
cout << "Test : " << tests[i].description << endl;
}
// Workers whose rank is inferior to required nodes number have to run the test, the other haven't anything to
// do.
if( Node::comm().rank() < tests[i].requiredNodesNumber )
{
job.run();
}
// After the job run, the master checks the result with offset and originalV
if( job.isMaster() )
{
// This job has to be instanciated, not launched, so as to tell the workers they're done with the parallel
// job.
EmptyJob stop( *(tests[i].assign), eo::mpi::DEFAULT_MASTER );
++offset;
for(unsigned i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
if( originalV[i] + offset != v[i] )
{
cout << " <-- ERROR at this point." << endl;
exit( EXIT_FAILURE );
}
}
cout << endl;
}
// MPI synchronization (all the processes wait to be here).
Node::comm().barrier();
delete tests[i].assign;
}
return 0;
}

View file

@ -0,0 +1,133 @@
/*
(c) Thales group, 2012
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact: http://eodev.sourceforge.net
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/*
* This file shows an example of how to wrap a handler of a job store. Here, the wrapped handler is the "IsFinished"
* one. The only function that has been added is that the wrapper prints a message on standard output, indicating what
* the wrapped function returns as a result.
*
* This test is performed on a parallel apply job, the same as in parallelApply. The main difference is when
* instanciating the store.
*/
# include <mpi/eoMpi.h>
# include <mpi/eoParallelApply.h>
# include <mpi/eoTerminateJob.h>
# include "t-mpi-common.h"
# include <iostream>
# include <cstdlib>
# include <vector>
using namespace std;
using namespace eo::mpi;
// Job functor.
struct plusOne : public eoUF< SerializableBase<int>&, void >
{
void operator() ( SerializableBase<int>& x )
{
++x;
}
};
/*
* Shows the wrapped result of IsFinished, prints a message and returns the wrapped value.
* times is an integer counting how many time the wrapper (hence the wrapped too) has been called.
*/
template< class EOT >
struct ShowWrappedResult : public IsFinishedParallelApply<EOT>
{
using IsFinishedParallelApply<EOT>::_wrapped;
ShowWrappedResult ( IsFinishedParallelApply<EOT> * w = 0 ) : IsFinishedParallelApply<EOT>( w ), times( 0 )
{
// empty
}
bool operator()()
{
bool wrappedValue = _wrapped->operator()(); // (*_wrapped)();
cout << times << ") Wrapped function would say that it is " << ( wrappedValue ? "":"not ") << "finished" << std::endl;
++times;
return wrappedValue;
}
private:
int times;
};
int main(int argc, char** argv)
{
// eo::log << eo::setlevel( eo::debug );
eo::log << eo::setlevel( eo::quiet );
Node::init( argc, argv );
srand( time(0) );
vector< SerializableBase<int> > v;
for( int i = 0; i < 1000; ++i )
{
v.push_back( rand() );
}
int offset = 0;
vector< SerializableBase<int> > originalV = v;
plusOne plusOneInstance;
StaticAssignmentAlgorithm assign( v.size() );
ParallelApplyStore< SerializableBase<int> > store( plusOneInstance, eo::mpi::DEFAULT_MASTER, 1 );
store.data( v );
// This is the only thing which changes: we wrap the IsFinished function.
// According to RAII, we'll delete the invokated wrapper at the end of the main ; the store won't delete it
// automatically.
ShowWrappedResult< SerializableBase<int> > wrapper;
store.wrapIsFinished( &wrapper );
ParallelApply< SerializableBase<int> > job( assign, eo::mpi::DEFAULT_MASTER, store );
// Equivalent to:
// Job< ParallelApplyData<int> > job( assign, 0, store );
job.run();
EmptyJob stop( assign, eo::mpi::DEFAULT_MASTER );
if( job.isMaster() )
{
++offset;
for(unsigned i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
if( originalV[i] + offset != v[i] )
{
cout << " <-- ERROR at this point." << endl;
exit( EXIT_FAILURE );
}
}
cout << endl;
}
return 0;
}

View file

@ -0,0 +1,104 @@
# include <mpi/eoMpi.h>
using namespace eo::mpi;
/*
* This file is a template for a new eo::mpi::Job. You have everything that should be necessary to implement a new
* parallelized algorithm.
*
* Replace __TEMPLATE__ by the name of your algorithm (for instance: MultiStart, ParallelApply, etc.).
*/
template< class EOT >
struct __TEMPLATE__Data
{
};
template< class EOT >
class SendTask__TEMPLATE__ : public SendTaskFunction< __TEMPLATE__Data< EOT > >
{
public:
using SendTaskFunction< __TEMPLATE__Data< EOT > >::_data;
void operator()( int wrkRank )
{
// TODO implement me
}
};
template< class EOT >
class HandleResponse__TEMPLATE__ : public HandleResponseFunction< __TEMPLATE__Data< EOT > >
{
public:
using HandleResponseFunction< __TEMPLATE__Data< EOT > >::_data;
void operator()( int wrkRank )
{
// TODO implement me
}
};
template< class EOT >
class ProcessTask__TEMPLATE__ : public ProcessTaskFunction< __TEMPLATE__Data< EOT > >
{
public:
using ProcessTaskFunction< __TEMPLATE__Data<EOT> >::_data;
void operator()()
{
// TODO implement me
}
};
template< class EOT >
class IsFinished__TEMPLATE__ : public IsFinishedFunction< __TEMPLATE__Data< EOT > >
{
public:
using IsFinishedFunction< __TEMPLATE__Data< EOT > >::_data;
bool operator()()
{
// TODO implement me
}
};
template< class EOT >
class __TEMPLATE__Store : public JobStore< __TEMPLATE__Data< EOT > >
{
public:
__TEMPLATE__Data<EOT>* data()
{
// TODO implement me
return 0;
}
};
template< class EOT >
class __TEMPLATE__ : public MultiJob< __TEMPLATE__Data< EOT > >
{
public:
__TEMPLATE__( AssignmentAlgorithm & algo,
int masterRank,
__TEMPLATE__Store< EOT > & store ) :
MultiJob< __TEMPLATE__Data< EOT > >( algo, masterRank, store )
{
// TODO implement me
}
};
/*
int main(int argc, char **argv)
{
Node::init( argc, argv );
DynamicAssignmentAlgorithm assignmentAlgo;
__TEMPLATE__Store<int> store;
__TEMPLATE__<int> job( assignmentAlgo, DEFAULT_MASTER, store );
}
*/

View file

@ -69,7 +69,8 @@ int main()
// Terminators
eoGenContinue<Chrom> continuator1(10);
eoFitContinue<Chrom> continuator2(CHROM_SIZE);
eoCombinedContinue<Chrom> continuator(continuator1, continuator2);
eoCombinedContinue<Chrom> continuator(continuator1);
continuator.add( continuator2 );
eoCheckPoint<Chrom> checkpoint(continuator);
eoStdoutMonitor monitor;
checkpoint.add(monitor);

View file

@ -73,7 +73,8 @@ int main()
// Terminators
eoGenContinue<Chrom> continuator1(10);
eoFitContinue<Chrom> continuator2(CHROM_SIZE);
eoCombinedContinue<Chrom> continuator(continuator1, continuator2);
eoCombinedContinue<Chrom> continuator(continuator1);
continuator.add( continuator2);
eoCheckPoint<Chrom> checkpoint(continuator);
eoStdoutMonitor monitor;
checkpoint.add(monitor);

View file

@ -72,7 +72,8 @@ int main()
// Terminators
eoGenContinue<Chrom> continuator1(10);
eoFitContinue<Chrom> continuator2(CHROM_SIZE);
eoCombinedContinue<Chrom> continuator(continuator1, continuator2);
eoCombinedContinue<Chrom> continuator(continuator1);
continuator.add(continuator2);
eoCheckPoint<Chrom> checkpoint(continuator);
eoStdoutMonitor monitor;
checkpoint.add(monitor);

View file

@ -0,0 +1,78 @@
#include <iostream>
#include <es/make_real.h>
#include <apply.h>
#include <eoEvalKeepBest.h>
#include "real_value.h"
using namespace std;
int main(int argc, char* argv[])
{
typedef eoReal<eoMinimizingFitness> EOT;
eoParser parser(argc, argv); // for user-parameter reading
eoState state; // keeps all things allocated
/*********************************************
* problem or representation dependent stuff *
*********************************************/
// The evaluation fn - encapsulated into an eval counter for output
eoEvalFuncPtr<EOT, double, const std::vector<double>&>
main_eval( real_value ); // use a function defined in real_value.h
// wrap the evaluation function in a call counter
eoEvalFuncCounter<EOT> eval_counter(main_eval);
// the genotype - through a genotype initializer
eoRealInitBounded<EOT>& init = make_genotype(parser, state, EOT());
// Build the variation operator (any seq/prop construct)
eoGenOp<EOT>& op = make_op(parser, state, init);
/*********************************************
* Now the representation-independent things *
*********************************************/
// initialize the population - and evaluate
// yes, this is representation indepedent once you have an eoInit
eoPop<EOT>& pop = make_pop(parser, state, init);
// stopping criteria
eoContinue<EOT> & term = make_continue(parser, state, eval_counter);
// things that are called at each generation
eoCheckPoint<EOT> & checkpoint = make_checkpoint(parser, state, eval_counter, term);
// wrap the evaluator in another one that will keep the best individual
// evaluated so far
eoEvalKeepBest<EOT> eval_keep( eval_counter );
// algorithm
eoAlgo<EOT>& ea = make_algo_scalar(parser, state, eval_keep, checkpoint, op);
/***************************************
* Now, call functors and DO something *
***************************************/
// to be called AFTER all parameters have been read!
make_help(parser);
// evaluate intial population AFTER help and status in case it takes time
apply<EOT>(eval_keep, pop);
std::clog << "Best individual after initialization and " << eval_counter.value() << " evaluations" << std::endl;
std::cout << eval_keep.best_element() << std::endl;
ea(pop); // run the ea
std::cout << "Best individual after search and " << eval_counter.value() << " evaluations" << std::endl;
// you can also call value(), because it is an eoParam
std::cout << eval_keep.value() << std::endl;
}

View file

@ -0,0 +1,98 @@
#include <iostream>
#include <vector>
#include <eo>
// An adhoc atom type of our own
class Quad : public std::vector<int>
{
public:
// Just four times zero
Quad() : std::vector<int>(4,0) {}
};
// EO somewhat forces you to implement a way to read/print your atom type
// You can either inherit from eoPrintable and overload readFrom/printOn
// or, just like here, directly overload stream operators.
// read
std::istream& operator>>( std::istream& is, Quad& q )
{
for( unsigned int i=0, n=4; i<n; ++i) {
// use default int stream input
is >> q[i];
}
return is;
}
// print
std::ostream& operator<<( std::ostream& os, const Quad& q )
{
os << q[0];
for( unsigned int i=1, n=4; i<n; ++i) {
os << " " << q[i];
}
os << " ";
return os;
}
// An init for the atoms
// Note that this mask the template passed to the eoInit
class QuadInit : public eoInit<Quad>
{
public:
// this is the API: an init modify the solution
void operator()( Quad& q ) {
for( unsigned int i=0, n=4; i<n; ++i) {
// rng is the random number generator of EO
q[i] = rng.random(10);
}
}
};
// The solution/individual type.
// Just a proxy to an eoVector of atoms,
// with a fitness as double.
class QuadVec : public eoVector<double,Quad>
{};
int main()
{
unsigned int vec_size_min = 1;
unsigned int vec_size_max = 10;
unsigned int pop_size = 10;
// Fix a seed for the random generator,
// thus, the results are predictable.
// Set it to zero if you want pseudo-random numbers
// that changes at each calls.
rng.reseed( 1 );
// The operator that produce a random vector of four values.
QuadInit atom_init;
// The operator that produces a random vector of a (vector of four values).
eoInitVariableLength<QuadVec> vec_init( vec_size_min, vec_size_max, atom_init );
// You can initialize a population of N individuals by passing an initializer to it.
eoPop<QuadVec> pop( pop_size, vec_init );
// eoPop can be printed easily,
// thanks to the overloadings above.
std::cout << pop << std::endl;
// With a seed at 1, this should output:
/*
10
INVALID 6 5 9 5 9 0 1 6 0 4 8 9 0 6 9 4 9 5 5 3 6 3 0 2 8
INVALID 9 9 2 0 3 2 4 3 3 6 2 8 2 4 5 4 7 5 3 0 5 4 9 8 3 2 7 7 9 4 4 4 6 6 3 9 2
INVALID 1 1 4 1 4
INVALID 5 3 8 9 8 8 1 4 1 6 6 5 4 3 2 7 5 1 2 6 1
INVALID 3 7 8 1 4 0 9 1 0 6 4 2 1
INVALID 6 7 4 6 8 1 2 6 0 5 1 2 6 9 2 6 8 6 1 5 5 4 1 0 3
INVALID 5 2 7 7 6 1 4 0 7 5 5 9 7 2 4 7 1 6 1 9 0
INVALID 3 5 5 3 9 2 9 9 1 1 7 2 1
INVALID 6 9 9 9 0 0 7 1 7 9 7 8 5 3 7 5 6 7 3 6 7 6 3 3 5
INVALID 1 6 2 4 3
*/
}

View file

@ -139,7 +139,8 @@ void main_function()
eoGenContinue<Chrom> continuator1(50);
eoFitContinue<Chrom> continuator2(65535.f);
eoCombinedContinue<Chrom> continuator(continuator1, continuator2);
eoCombinedContinue<Chrom> continuator(continuator1);
continuator.add( continuator2);
eoCheckPoint<Chrom> checkpoint(continuator);

View file

@ -2,63 +2,63 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/ga)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/utils)
include_directories(${EO_SRC_DIR}/src)
include_directories(${EO_SRC_DIR}/src/ga)
include_directories(${EO_SRC_DIR}/src/utils)
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
IF(NOT WIN32 OR CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
ENDIF(NOT WIN32 OR CYGWIN)
if(NOT WIN32 OR CYGWIN)
link_directories(${EO_BIN_DIR}/lib)
endif(NOT WIN32 OR CYGWIN)
# especially for Visual Studio
IF(WIN32 AND NOT CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}\\lib\\${CMAKE_BUILD_TYPE})
ENDIF(WIN32 AND NOT CYGWIN)
if(WIN32 AND NOT CYGWIN)
link_directories(${EO_BIN_DIR}\\lib\\${CMAKE_BUILD_TYPE})
endif(WIN32 AND NOT CYGWIN)
######################################################################################
### 3) Define your targets
######################################################################################
# no matter what is the OS, hopefully
ADD_EXECUTABLE(FirstBitGA FirstBitGA.cpp)
ADD_EXECUTABLE(FirstRealGA FirstRealGA.cpp)
ADD_EXECUTABLE(exercise1.3 exercise1.3.cpp)
add_executable(FirstBitGA FirstBitGA.cpp)
add_executable(FirstRealGA FirstRealGA.cpp)
add_executable(exercise1.3 exercise1.3.cpp)
ADD_DEPENDENCIES(FirstBitGA ga eo eoutils)
ADD_DEPENDENCIES(FirstRealGA ga eo eoutils)
ADD_DEPENDENCIES(exercise1.3 ga eo eoutils)
add_dependencies(FirstBitGA ga eo eoutils)
add_dependencies(FirstRealGA ga eo eoutils)
add_dependencies(exercise1.3 ga eo eoutils)
######################################################################################
### 4) Optionnal
######################################################################################
SET(FIRSTBITGA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(FirstBitGA PROPERTIES VERSION "${FIRSTBITGA_VERSION}")
set(FIRSTBITGA_VERSION ${GLOBAL_VERSION})
set_target_properties(FirstBitGA PROPERTIES VERSION "${FIRSTBITGA_VERSION}")
SET(FIRSTREALGA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(FirstRealGA PROPERTIES VERSION "${FIRSTREALGA_VERSION}")
set(FIRSTREALGA_VERSION ${GLOBAL_VERSION})
set_target_properties(FirstRealGA PROPERTIES VERSION "${FIRSTREALGA_VERSION}")
SET(EXERCICE13_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(exercise1.3 PROPERTIES VERSION "${EXERCICE13_VERSION}")
set(EXERCICE13_VERSION ${GLOBAL_VERSION})
set_target_properties(exercise1.3 PROPERTIES VERSION "${EXERCICE13_VERSION}")
######################################################################################
### 5) Link the librairies for the targets
######################################################################################
TARGET_LINK_LIBRARIES(FirstBitGA ga eo eoutils)
TARGET_LINK_LIBRARIES(FirstRealGA ga eo eoutils)
TARGET_LINK_LIBRARIES(exercise1.3 ga eo eoutils)
target_link_libraries(FirstBitGA ga eo eoutils)
target_link_libraries(FirstRealGA ga eo eoutils)
target_link_libraries(exercise1.3 ga eo eoutils)
######################################################################################
### 6) Configure project installation paths
######################################################################################
INSTALL(TARGETS FirstBitGA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson1 COMPONENT examples)
INSTALL(TARGETS FirstRealGA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson1 COMPONENT examples)
INSTALL(TARGETS exercise1.3 RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson1 COMPONENT examples)
install(TARGETS FirstBitGA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson1 COMPONENT examples)
install(TARGETS FirstRealGA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson1 COMPONENT examples)
install(TARGETS exercise1.3 RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson1 COMPONENT examples)
######################################################################################

View file

@ -2,59 +2,59 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/ga)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/utils)
include_directories(${EO_SRC_DIR}/src)
include_directories(${EO_SRC_DIR}/src/ga)
include_directories(${EO_SRC_DIR}/src/utils)
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
IF(NOT WIN32 OR CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
ENDIF(NOT WIN32 OR CYGWIN)
if(NOT WIN32 OR CYGWIN)
link_directories(${EO_BIN_DIR}/lib)
endif(NOT WIN32 OR CYGWIN)
# especially for Visual Studio
IF(WIN32 AND NOT CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}\\lib\\${CMAKE_BUILD_TYPE})
ENDIF(WIN32 AND NOT CYGWIN)
if(WIN32 AND NOT CYGWIN)
link_directories(${EO_BIN_DIR}\\lib\\${CMAKE_BUILD_TYPE})
endif(WIN32 AND NOT CYGWIN)
######################################################################################
### 3) Define your targets
######################################################################################
# no matter what is the OS, hopefully
ADD_EXECUTABLE(FirstBitEA FirstBitEA.cpp)
ADD_EXECUTABLE(FirstRealEA FirstRealEA.cpp)
ADD_EXECUTABLE(exercise2.3 exercise2.3.cpp)
add_executable(FirstBitEA FirstBitEA.cpp)
add_executable(FirstRealEA FirstRealEA.cpp)
add_executable(exercise2.3 exercise2.3.cpp)
######################################################################################
### 4) Optionnal
######################################################################################
SET(FIRSTBITEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(FirstBitEA PROPERTIES VERSION "${FIRSTBITEA_VERSION}")
set(FIRSTBITEA_VERSION ${GLOBAL_VERSION})
set_target_properties(FirstBitEA PROPERTIES VERSION "${FIRSTBITEA_VERSION}")
SET(FIRSTREALEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(FirstRealEA PROPERTIES VERSION "${FIRSTREALEA_VERSION}")
set(FIRSTREALEA_VERSION ${GLOBAL_VERSION})
set_target_properties(FirstRealEA PROPERTIES VERSION "${FIRSTREALEA_VERSION}")
SET(EXERCICE23_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(exercise2.3 PROPERTIES VERSION "${EXERCICE23_VERSION}")
set(EXERCICE23_VERSION ${GLOBAL_VERSION})
set_target_properties(exercise2.3 PROPERTIES VERSION "${EXERCICE23_VERSION}")
######################################################################################
### 5) Link the librairies for the targets
######################################################################################
TARGET_LINK_LIBRARIES(FirstBitEA ga eo eoutils)
TARGET_LINK_LIBRARIES(FirstRealEA ga eo eoutils)
TARGET_LINK_LIBRARIES(exercise2.3 ga eo eoutils)
target_link_libraries(FirstBitEA ga eo eoutils)
target_link_libraries(FirstRealEA ga eo eoutils)
target_link_libraries(exercise2.3 ga eo eoutils)
######################################################################################
### 6) Configure project installation paths
######################################################################################
INSTALL(TARGETS FirstBitEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson2 COMPONENT examples)
INSTALL(TARGETS FirstRealEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson2 COMPONENT examples)
INSTALL(TARGETS exercise2.3 RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson2 COMPONENT examples)
install(TARGETS FirstBitEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson2 COMPONENT examples)
install(TARGETS FirstRealEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson2 COMPONENT examples)
install(TARGETS exercise2.3 RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson2 COMPONENT examples)
######################################################################################

View file

@ -2,63 +2,63 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/ga)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/utils)
include_directories(${EO_SRC_DIR}/src)
include_directories(${EO_SRC_DIR}/src/ga)
include_directories(${EO_SRC_DIR}/src/utils)
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
IF(NOT WIN32 OR CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
ENDIF(NOT WIN32 OR CYGWIN)
if(NOT WIN32 OR CYGWIN)
link_directories(${EO_BIN_DIR}/lib)
endif(NOT WIN32 OR CYGWIN)
# especially for Visual Studio
IF(WIN32 AND NOT CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}\\lib\\${CMAKE_BUILD_TYPE})
ENDIF(WIN32 AND NOT CYGWIN)
if(WIN32 AND NOT CYGWIN)
link_directories(${EO_BIN_DIR}\\lib\\${CMAKE_BUILD_TYPE})
endif(WIN32 AND NOT CYGWIN)
######################################################################################
### 3) Define your targets
######################################################################################
# no matter what is the OS, hopefully
ADD_EXECUTABLE(SecondBitEA SecondBitEA.cpp)
ADD_EXECUTABLE(SecondRealEA SecondRealEA.cpp)
ADD_EXECUTABLE(exercise3.1 exercise3.1.cpp)
add_executable(SecondBitEA SecondBitEA.cpp)
add_executable(SecondRealEA SecondRealEA.cpp)
add_executable(exercise3.1 exercise3.1.cpp)
ADD_DEPENDENCIES(SecondBitEA ga eoutils eo)
ADD_DEPENDENCIES(SecondRealEA ga eoutils eo)
ADD_DEPENDENCIES(exercise3.1 ga eoutils eo)
add_dependencies(SecondBitEA ga eoutils eo)
add_dependencies(SecondRealEA ga eoutils eo)
add_dependencies(exercise3.1 ga eoutils eo)
######################################################################################
### 4) Optionnal
######################################################################################
SET(SECONDBITEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(SecondBitEA PROPERTIES VERSION "${SECONDBITEA_VERSION}")
set(SECONDBITEA_VERSION ${GLOBAL_VERSION})
set_target_properties(SecondBitEA PROPERTIES VERSION "${SECONDBITEA_VERSION}")
SET(SECONDREALEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(SecondRealEA PROPERTIES VERSION "${SECONDREALEA_VERSION}")
set(SECONDREALEA_VERSION ${GLOBAL_VERSION})
set_target_properties(SecondRealEA PROPERTIES VERSION "${SECONDREALEA_VERSION}")
SET(EXERCICE31_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(exercise3.1 PROPERTIES VERSION "${EXERCICE31_VERSION}")
set(EXERCICE31_VERSION ${GLOBAL_VERSION})
set_target_properties(exercise3.1 PROPERTIES VERSION "${EXERCICE31_VERSION}")
######################################################################################
### 5) Link the librairies for the targets
######################################################################################
TARGET_LINK_LIBRARIES(SecondBitEA ga eoutils eo)
TARGET_LINK_LIBRARIES(SecondRealEA ga eoutils eo)
TARGET_LINK_LIBRARIES(exercise3.1 ga eoutils eo)
target_link_libraries(SecondBitEA ga eoutils eo)
target_link_libraries(SecondRealEA ga eoutils eo)
target_link_libraries(exercise3.1 ga eoutils eo)
######################################################################################
### 6) Configure project installation paths
######################################################################################
INSTALL(TARGETS SecondBitEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson3 COMPONENT examples)
INSTALL(TARGETS SecondRealEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson3 COMPONENT examples)
INSTALL(TARGETS exercise3.1 RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson3 COMPONENT examples)
install(TARGETS SecondBitEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson3 COMPONENT examples)
install(TARGETS SecondRealEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson3 COMPONENT examples)
install(TARGETS exercise3.1 RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson3 COMPONENT examples)
######################################################################################

View file

@ -2,97 +2,97 @@
### 0) Copy the ESEA.param and RealEA.param files in the build directory for an easy use.
######################################################################################
EXECUTE_PROCESS(
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${EO_SOURCE_DIR}/tutorial/Lesson4/ESEA.param
${EO_BINARY_DIR}/tutorial/Lesson4/ESEA.param
${EO_SRC_DIR}/tutorial/Lesson4/ESEA.param
${EO_BIN_DIR}/tutorial/Lesson4/ESEA.param
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${EO_SOURCE_DIR}/tutorial/Lesson4/RealEA.param
${EO_BINARY_DIR}/tutorial/Lesson4/RealEA.param
${EO_SRC_DIR}/tutorial/Lesson4/RealEA.param
${EO_BIN_DIR}/tutorial/Lesson4/RealEA.param
)
##############
# OLD_TARGETS
##############
#ADD_CUSTOM_TARGET(param DEPENDS ${EO_SOURCE_DIR}/tutorial/Lesson4/ESEA.param)
#ADD_CUSTOM_COMMAND(
#add_custom_target(param DEPENDS ${EO_SRC_DIR}/tutorial/Lesson4/ESEA.param)
#add_custom_command(
# TARGET param
# POST_BUILD
# COMMAND ${CMAKE_COMMAND}
# ARGS -E copy_if_different
# ${EO_SOURCE_DIR}/tutorial/Lesson4/ESEA.param
# ${EO_BINARY_DIR}/tutorial/Lesson4)
#ADD_CUSTOM_TARGET(param DEPENDS ${EO_SOURCE_DIR}/tutorial/Lesson4/RealEA.param)
#ADD_CUSTOM_COMMAND(
# ${EO_SRC_DIR}/tutorial/Lesson4/ESEA.param
# ${EO_BIN_DIR}/tutorial/Lesson4)
#add_custom_target(param DEPENDS ${EO_SRC_DIR}/tutorial/Lesson4/RealEA.param)
#add_custom_command(
# TARGET param
# POST_BUILD
# COMMAND ${CMAKE_COMMAND}
# ARGS -E copy_if_different
# ${EO_SOURCE_DIR}/tutorial/Lesson4/RealEA.param
# ${EO_BINARY_DIR}/tutorial/Lesson4)
# ${EO_SRC_DIR}/tutorial/Lesson4/RealEA.param
# ${EO_BIN_DIR}/tutorial/Lesson4)
######################################################################################
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/es)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/utils)
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src/ga)
include_directories(${EO_SRC_DIR}/src)
include_directories(${EO_SRC_DIR}/src/es)
include_directories(${EO_SRC_DIR}/src/utils)
include_directories(${EO_SRC_DIR}/src/ga)
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
IF(NOT WIN32 OR CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
ENDIF(NOT WIN32 OR CYGWIN)
if(NOT WIN32 OR CYGWIN)
link_directories(${EO_BIN_DIR}/lib)
endif(NOT WIN32 OR CYGWIN)
# especially for Visual Studio
IF(WIN32 AND NOT CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}\\lib\\${CMAKE_BUILD_TYPE})
ENDIF(WIN32 AND NOT CYGWIN)
if(WIN32 AND NOT CYGWIN)
link_directories(${EO_BIN_DIR}\\lib\\${CMAKE_BUILD_TYPE})
endif(WIN32 AND NOT CYGWIN)
######################################################################################
### 3) Define your targets
######################################################################################
# no matter what is the OS, hopefully
ADD_EXECUTABLE(BitEA BitEA.cpp)
ADD_EXECUTABLE(RealEA RealEA.cpp)
ADD_EXECUTABLE(ESEA ESEA.cpp)
add_executable(BitEA BitEA.cpp)
add_executable(RealEA RealEA.cpp)
add_executable(ESEA ESEA.cpp)
#ADD_DEPENDENCIES(BitEA es ga eo eoutils)
#ADD_DEPENDENCIES(RealEA es ga eo eoutils)
#ADD_DEPENDENCIES(ESEA es ga eo eoutils)
#add_dependencies(BitEA es ga eo eoutils)
#add_dependencies(RealEA es ga eo eoutils)
#add_dependencies(ESEA es ga eo eoutils)
######################################################################################
### 4) Optionnal
######################################################################################
SET(BITEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(BitEA PROPERTIES VERSION "${BITEA_VERSION}")
set(BITEA_VERSION ${GLOBAL_VERSION})
set_target_properties(BitEA PROPERTIES VERSION "${BITEA_VERSION}")
SET(REALEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(RealEA PROPERTIES VERSION "${REALEA_VERSION}")
set(REALEA_VERSION ${GLOBAL_VERSION})
set_target_properties(RealEA PROPERTIES VERSION "${REALEA_VERSION}")
SET(ESEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(ESEA PROPERTIES VERSION "${ESEA_VERSION}")
set(ESEA_VERSION ${GLOBAL_VERSION})
set_target_properties(ESEA PROPERTIES VERSION "${ESEA_VERSION}")
######################################################################################
### 5) Link the librairies for the targets
######################################################################################
TARGET_LINK_LIBRARIES(BitEA es ga eo eoutils)
TARGET_LINK_LIBRARIES(RealEA es ga eo eoutils)
TARGET_LINK_LIBRARIES(ESEA es ga eo eoutils)
target_link_libraries(BitEA es ga eo eoutils)
target_link_libraries(RealEA es ga eo eoutils)
target_link_libraries(ESEA es ga eo eoutils)
######################################################################################
### 6) Configure project installation paths
######################################################################################
INSTALL(TARGETS BitEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson4 COMPONENT examples)
INSTALL(TARGETS RealEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson4 COMPONENT examples)
INSTALL(TARGETS ESEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson4 COMPONENT examples)
install(TARGETS BitEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson4 COMPONENT examples)
install(TARGETS RealEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson4 COMPONENT examples)
install(TARGETS ESEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson4 COMPONENT examples)
######################################################################################

View file

@ -2,55 +2,55 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${EO_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
IF(NOT WIN32 OR CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
ENDIF(NOT WIN32 OR CYGWIN)
if(NOT WIN32 OR CYGWIN)
link_directories(${EO_BIN_DIR}/lib)
endif(NOT WIN32 OR CYGWIN)
# especially for Visual Studio
IF(WIN32 AND NOT CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}\\lib\\${CMAKE_BUILD_TYPE})
ENDIF(WIN32 AND NOT CYGWIN)
if(WIN32 AND NOT CYGWIN)
link_directories(${EO_BIN_DIR}\\lib\\${CMAKE_BUILD_TYPE})
endif(WIN32 AND NOT CYGWIN)
######################################################################################
### 3) Define your targets
######################################################################################
# no matter what is the OS, hopefully
ADD_EXECUTABLE(OneMaxEA OneMaxEA.cpp)
ADD_EXECUTABLE(OneMaxLibEA OneMaxLibEA.cpp make_OneMax.cpp)
add_executable(OneMaxEA OneMaxEA.cpp)
add_executable(OneMaxLibEA OneMaxLibEA.cpp make_OneMax.cpp)
ADD_DEPENDENCIES(OneMaxEA es ga eo eoutils)
ADD_DEPENDENCIES(OneMaxLibEA es ga eo eoutils)
add_dependencies(OneMaxEA es ga eo eoutils)
add_dependencies(OneMaxLibEA es ga eo eoutils)
######################################################################################
### 4) Optionnal
######################################################################################
SET(ONEMAXEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(OneMaxEA PROPERTIES VERSION "${ONEMAXEA_VERSION}")
set(ONEMAXEA_VERSION ${GLOBAL_VERSION})
set_target_properties(OneMaxEA PROPERTIES VERSION "${ONEMAXEA_VERSION}")
SET(ONEMAXLIBEA_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(OneMaxLibEA PROPERTIES VERSION "${ONEMAXLIBEA_VERSION}")
set(ONEMAXLIBEA_VERSION ${GLOBAL_VERSION})
set_target_properties(OneMaxLibEA PROPERTIES VERSION "${ONEMAXLIBEA_VERSION}")
######################################################################################
### 5) Link the librairies for the targets
######################################################################################
TARGET_LINK_LIBRARIES(OneMaxEA es ga eo eoutils)
TARGET_LINK_LIBRARIES(OneMaxLibEA es ga eo eoutils)
target_link_libraries(OneMaxEA es ga eo eoutils)
target_link_libraries(OneMaxLibEA es ga eo eoutils)
######################################################################################
### 6) Configure project installation paths
######################################################################################
INSTALL(TARGETS OneMaxEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson5 COMPONENT examples)
INSTALL(TARGETS OneMaxLibEA RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson5 COMPONENT examples)
install(TARGETS OneMaxEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson5 COMPONENT examples)
install(TARGETS OneMaxLibEA RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson5 COMPONENT examples)
######################################################################################

View file

@ -2,50 +2,50 @@
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
include_directories(${EO_SRC_DIR}/src)
######################################################################################
### 2) Specify where CMake can find the libraries
######################################################################################
IF(NOT WIN32 OR CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}/lib)
ENDIF(NOT WIN32 OR CYGWIN)
if(NOT WIN32 OR CYGWIN)
link_directories(${EO_BIN_DIR}/lib)
endif(NOT WIN32 OR CYGWIN)
# especially for Visual Studio
IF(WIN32 AND NOT CYGWIN)
LINK_DIRECTORIES(${EO_BINARY_DIR}\\lib\\${CMAKE_BUILD_TYPE})
ENDIF(WIN32 AND NOT CYGWIN)
if(WIN32 AND NOT CYGWIN)
link_directories(${EO_BIN_DIR}\\lib\\${CMAKE_BUILD_TYPE})
endif(WIN32 AND NOT CYGWIN)
######################################################################################
### 3) Define your targets
######################################################################################
ADD_EXECUTABLE(BinaryPSO BinaryPSO.cpp)
ADD_EXECUTABLE(RealPSO RealPSO.cpp)
add_executable(BinaryPSO BinaryPSO.cpp)
add_executable(RealPSO RealPSO.cpp)
######################################################################################
### 4) Optionnal
######################################################################################
SET(BINARYPSO_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(BinaryPSO PROPERTIES VERSION "${BINARYPSO_VERSION}")
set(BINARYPSO_VERSION ${GLOBAL_VERSION})
set_target_properties(BinaryPSO PROPERTIES VERSION "${BINARYPSO_VERSION}")
SET(REALPSO_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(RealPSO PROPERTIES VERSION "${REALPSO_VERSION}")
set(REALPSO_VERSION ${GLOBAL_VERSION})
set_target_properties(RealPSO PROPERTIES VERSION "${REALPSO_VERSION}")
######################################################################################
### 5) Link the librairies for the targets
######################################################################################
TARGET_LINK_LIBRARIES(BinaryPSO eo eoutils)
TARGET_LINK_LIBRARIES(RealPSO eo eoutils)
target_link_libraries(BinaryPSO eo eoutils)
target_link_libraries(RealPSO eo eoutils)
######################################################################################
### 6) Configure project installation paths
######################################################################################
INSTALL(TARGETS BinaryPSO RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson6 COMPONENT examples)
INSTALL(TARGETS RealPSO RUNTIME DESTINATION share${INSTALL_SUB_DIR}/eo/examples/Lesson6 COMPONENT examples)
install(TARGETS BinaryPSO RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson6 COMPONENT examples)
install(TARGETS RealPSO RUNTIME DESTINATION local/share${INSTALL_SUB_DIR}/eo/examples/Lesson6 COMPONENT examples)
######################################################################################

View file

@ -0,0 +1,63 @@
How to install EoMPI
====================
Install OpenMpi
---------------
1) Download OpenMPI on their website or with the following command:
wget http://www.open-mpi.org/software/ompi/v1.6/downloads/openmpi-1.6.tar.bz2
2) Untar the downloaded archive in a directory and change working directory to there:
tar -xvjf openmpi*.tar.bz2
cd openmpi-X.Y
3) Use configuration script to indicate in which directory OpenMPI should be installed, and other options:
Simplest configuration:
./configure --prefix=/home/`whoami`/openmpi/
Only static libraries:
./configure --enable-static --disable-shared
Only static libraries, with prefix, disable build for Fortran77 and Fortran90, add support for SGE:
./configure --enable-static --disable-shared --prefix=/home/`whoami`/openmpi/ --disable-mpi-f77 --disable-mpi-f90 --with-sge
Other options are available in the README file.
4) Make it and install:
In sequential:
make all install
Or in parallel:
make -j 2 all
make install
5) Try to compile and run the sample program:
~/openmpi/bin/mpicxx -o sample mpi.c
~/openmpi/bin/mpirun -np 3 ./sample
Configure EO to use MPI
-----------------------
You only need to configure eo-conf.cmake so as to use MPI :
1) Put the WITH_MPI boolean to true:
SET(WITH_MPI TRUE CACHE BOOL "Use mpi ?" FORCE)
2) Indicate in which directories you have installed openmpi:
SET(MPI_DIR "/where/did/you/install/openmpi" CACHE PATH "OpenMPI directory" FORCE)
3) Recompile eo:
./distclean
./build_gcc_linux_release.sh
4) If you meet any issue, don't hesitate to contact the EO mailing list:
eodev-main@lists.sourceforge.net

View file

@ -0,0 +1,405 @@
html {
height: 100%;
}
body.deck-container {
overflow-y: auto;
position: static;
}
.deck-container {
position: relative;
min-height: 100%;
margin: 0 auto;
padding: 0 48px;
font-size: 16px;
line-height: 1.25;
overflow: hidden;
/* Resets and base styles from HTML5 Boilerplate */
/* End HTML5 Boilerplate adaptations */
}
.js .deck-container {
visibility: hidden;
}
.ready .deck-container {
visibility: visible;
}
.touch .deck-container {
-webkit-text-size-adjust: none;
-moz-text-size-adjust: none;
}
.deck-container div, .deck-container span, .deck-container object, .deck-container iframe,
.deck-container h1, .deck-container h2, .deck-container h3, .deck-container h4, .deck-container h5, .deck-container h6, .deck-container p, .deck-container blockquote, .deck-container pre,
.deck-container abbr, .deck-container address, .deck-container cite, .deck-container code, .deck-container del, .deck-container dfn, .deck-container em, .deck-container img, .deck-container ins, .deck-container kbd, .deck-container q, .deck-container samp,
.deck-container small, .deck-container strong, .deck-container sub, .deck-container sup, .deck-container var, .deck-container b, .deck-container i, .deck-container dl, .deck-container dt, .deck-container dd, .deck-container ol, .deck-container ul, .deck-container li,
.deck-container fieldset, .deck-container form, .deck-container label, .deck-container legend,
.deck-container table, .deck-container caption, .deck-container tbody, .deck-container tfoot, .deck-container thead, .deck-container tr, .deck-container th, .deck-container td,
.deck-container article, .deck-container aside, .deck-container canvas, .deck-container details, .deck-container figcaption, .deck-container figure,
.deck-container footer, .deck-container header, .deck-container hgroup, .deck-container menu, .deck-container nav, .deck-container section, .deck-container summary,
.deck-container time, .deck-container mark, .deck-container audio, .deck-container video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
.deck-container article, .deck-container aside, .deck-container details, .deck-container figcaption, .deck-container figure,
.deck-container footer, .deck-container header, .deck-container hgroup, .deck-container menu, .deck-container nav, .deck-container section {
display: block;
}
.deck-container blockquote, .deck-container q {
quotes: none;
}
.deck-container blockquote:before, .deck-container blockquote:after, .deck-container q:before, .deck-container q:after {
content: "";
content: none;
}
.deck-container ins {
background-color: #ff9;
color: #000;
text-decoration: none;
}
.deck-container mark {
background-color: #ff9;
color: #000;
font-style: italic;
font-weight: bold;
}
.deck-container del {
text-decoration: line-through;
}
.deck-container abbr[title], .deck-container dfn[title] {
border-bottom: 1px dotted;
cursor: help;
}
.deck-container table {
border-collapse: collapse;
border-spacing: 0;
}
.deck-container hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0;
}
.deck-container input, .deck-container select {
vertical-align: middle;
}
.deck-container select, .deck-container input, .deck-container textarea, .deck-container button {
font: 99% sans-serif;
}
.deck-container pre, .deck-container code, .deck-container kbd, .deck-container samp {
font-family: monospace, sans-serif;
}
.deck-container a {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.deck-container a:hover, .deck-container a:active {
outline: none;
}
.deck-container ul, .deck-container ol {
margin-left: 2em;
vertical-align: top;
}
.deck-container ol {
list-style-type: decimal;
}
.deck-container nav ul, .deck-container nav li {
margin: 0;
list-style: none;
list-style-image: none;
}
.deck-container small {
font-size: 85%;
}
.deck-container strong, .deck-container th {
font-weight: bold;
}
.deck-container td {
vertical-align: top;
}
.deck-container sub, .deck-container sup {
font-size: 75%;
line-height: 0;
position: relative;
}
.deck-container sup {
top: -0.5em;
}
.deck-container sub {
bottom: -0.25em;
}
.deck-container textarea {
overflow: auto;
}
.ie6 .deck-container legend, .ie7 .deck-container legend {
margin-left: -7px;
}
.deck-container input[type="radio"] {
vertical-align: text-bottom;
}
.deck-container input[type="checkbox"] {
vertical-align: bottom;
}
.ie7 .deck-container input[type="checkbox"] {
vertical-align: baseline;
}
.ie6 .deck-container input {
vertical-align: text-bottom;
}
.deck-container label, .deck-container input[type="button"], .deck-container input[type="submit"], .deck-container input[type="image"], .deck-container button {
cursor: pointer;
}
.deck-container button, .deck-container input, .deck-container select, .deck-container textarea {
margin: 0;
}
.deck-container input:invalid, .deck-container textarea:invalid {
border-radius: 1px;
-moz-box-shadow: 0px 0px 5px red;
-webkit-box-shadow: 0px 0px 5px red;
box-shadow: 0px 0px 5px red;
}
.deck-container input:invalid .no-boxshadow, .deck-container textarea:invalid .no-boxshadow {
background-color: #f0dddd;
}
.deck-container button {
width: auto;
overflow: visible;
}
.ie7 .deck-container img {
-ms-interpolation-mode: bicubic;
}
.deck-container, .deck-container select, .deck-container input, .deck-container textarea {
color: #444;
}
.deck-container a {
color: #607890;
}
.deck-container a:hover, .deck-container a:focus {
color: #036;
}
.deck-container a:link {
-webkit-tap-highlight-color: #fff;
}
.deck-container.deck-loading {
display: none;
}
.slide {
width: auto;
min-height: 100%;
position: relative;
}
.slide h1 {
font-size: 4.5em;
}
.slide h1, .slide .vcenter {
font-weight: bold;
text-align: center;
padding-top: 1em;
max-height: 100%;
}
.csstransforms .slide h1, .csstransforms .slide .vcenter {
padding: 0 48px;
position: absolute;
left: 0;
right: 0;
top: 50%;
-webkit-transform: translate(0, -50%);
-moz-transform: translate(0, -50%);
-ms-transform: translate(0, -50%);
-o-transform: translate(0, -50%);
transform: translate(0, -50%);
}
.slide .vcenter h1 {
position: relative;
top: auto;
padding: 0;
-webkit-transform: none;
-moz-transform: none;
-ms-transform: none;
-o-transform: none;
transform: none;
}
.slide h2 {
font-size: 2.25em;
font-weight: bold;
padding-top: .5em;
margin: 0 0 .66666em 0;
border-bottom: 3px solid #888;
}
.slide h3 {
font-size: 1.4375em;
font-weight: bold;
margin-bottom: .30435em;
}
.slide h4 {
font-size: 1.25em;
font-weight: bold;
margin-bottom: .25em;
}
.slide h5 {
font-size: 1.125em;
font-weight: bold;
margin-bottom: .2222em;
}
.slide h6 {
font-size: 1em;
font-weight: bold;
}
.slide img, .slide iframe, .slide video {
display: block;
max-width: 100%;
}
.slide video, .slide iframe, .slide img {
display: block;
margin: 0 auto;
}
.slide p, .slide blockquote, .slide iframe, .slide img, .slide ul, .slide ol, .slide pre, .slide video {
margin-bottom: 1em;
}
.slide pre {
white-space: pre;
white-space: pre-wrap;
word-wrap: break-word;
padding: 1em;
border: 1px solid #888;
}
.slide em {
font-style: italic;
}
.slide li {
padding: .25em 0;
vertical-align: middle;
}
.deck-before, .deck-previous, .deck-next, .deck-after {
position: absolute;
left: -999em;
top: -999em;
}
.deck-current {
z-index: 2;
}
.slide .slide {
visibility: hidden;
position: static;
min-height: 0;
}
.deck-child-current {
position: static;
z-index: 2;
}
.deck-child-current .slide {
visibility: hidden;
}
.deck-child-current .deck-previous, .deck-child-current .deck-before, .deck-child-current .deck-current {
visibility: visible;
}
@media screen and (max-device-width: 480px) {
/* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
}
@media print {
* {
background: transparent !important;
color: black !important;
text-shadow: none !important;
filter: none !important;
-ms-filter: none !important;
-webkit-box-reflect: none !important;
-moz-box-reflect: none !important;
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
box-shadow: none !important;
}
* :before, * :after {
display: none !important;
}
a, a:visited {
color: #444 !important;
text-decoration: underline;
}
a[href]:after {
content: " (" attr(href) ")";
}
abbr[title]:after {
content: " (" attr(title) ")";
}
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after {
content: "";
}
pre, blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
thead {
display: table-header-group;
}
tr, img {
page-break-inside: avoid;
}
@page {
margin: 0.5cm;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3 {
page-break-after: avoid;
}
.slide {
position: static !important;
visibility: visible !important;
display: block !important;
-webkit-transform: none !important;
-moz-transform: none !important;
-o-transform: none !important;
-ms-transform: none !important;
transform: none !important;
opacity: 1 !important;
}
h1, .vcenter {
-webkit-transform: none !important;
-moz-transform: none !important;
-o-transform: none !important;
-ms-transform: none !important;
transform: none !important;
padding: 0 !important;
position: static !important;
}
.deck-container > .slide {
page-break-after: always;
}
.deck-container {
width: 100% !important;
height: auto !important;
padding: 0 !important;
display: block !important;
}
script {
display: none;
}
}

View file

@ -0,0 +1,41 @@
.deck-container .goto-form {
position: absolute;
z-index: 3;
bottom: 10px;
left: 50%;
height: 1.75em;
margin: 0 0 0 -9.125em;
line-height: 1.75em;
padding: 0.625em;
display: none;
background: #ccc;
overflow: hidden;
}
.borderradius .deck-container .goto-form {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
.deck-container .goto-form label {
font-weight: bold;
}
.deck-container .goto-form label, .deck-container .goto-form input {
display: inline-block;
font-family: inherit;
}
.deck-goto .goto-form {
display: block;
}
#goto-slide {
width: 8.375em;
margin: 0 0.625em;
height: 1.4375em;
}
@media print {
.goto-form, #goto-slide {
display: none !important;
}
}

View file

@ -0,0 +1,13 @@
.deck-container .deck-permalink {
display: none;
position: absolute;
z-index: 4;
bottom: 30px;
right: 0;
width: 48px;
text-align: center;
}
.no-history .deck-container:hover .deck-permalink {
display: block;
}

Some files were not shown because too many files have changed in this diff Show more