Add the SMP module

git-svn-id: svn://scm.gforge.inria.fr/svnroot/paradiseo@2714 331e1502-861f-0410-8da2-ba01fb791d7f
This commit is contained in:
quemy 2012-08-17 11:52:14 +00:00
commit 0890c67d31
43 changed files with 4030 additions and 41 deletions

View file

@ -0,0 +1,40 @@
######################################################################################
### 0) Include headers
######################################################################################
include_directories(${EO_SRC_DIR}/src)
include_directories(${SMP_SRC_DIR}/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 1) Define test list
######################################################################################
set (TEST_LIST
t-smpThread
t-smpScheduler
t-smpMW_eoEasyEA
t-smpMW_eoEasyPSO
t-smpMW_eoSyncEasyPSO
)
######################################################################################
### 3) Create each test
######################################################################################
foreach (test ${TEST_LIST})
set ("T_${test}_SOURCES" "${test}.cpp")
add_executable(${test} ${T_${test}_SOURCES})
target_link_libraries(${test} smp eo eoutils)
add_test(${test} ${test})
endforeach (test)
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/t-data.dat
${CMAKE_CURRENT_BINARY_DIR}/t-data.dat)
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/bench.sh
${CMAKE_CURRENT_BINARY_DIR}/bench.sh)

View file

@ -0,0 +1,272 @@
#ifndef _SMPTEST_H
#define _SMPTEST_H
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <thread>
#include <chrono>
using namespace std;
int n = 10;
int** a;
int** b;
int bkv; //best known value
struct parameters
{
unsigned seed ;
int popSize;
int tSize;
string inst;
string loadName;
string schema;
double pCross;
double pMut;
int minGen;
int maxGen;
};
class Indi : public EO<eoMinimizingFitness> {
public:
int* solution;
int evalNb = 0;
Indi () {
solution = new int[n];
create();
}
Indi (const Indi & _problem){ // copy constructor
solution = new int[n];
for (int i = 0; i < n ; i++){
solution[i] = _problem.solution[i];
}
if (!_problem.invalid()) // if the solution has already been evaluated
fitness(_problem.fitness()); // copy the fitness
}
~Indi(){ // destructor
delete[] solution;
}
void operator= (const Indi & _problem){ // copy assignment operator
for (int i = 0; i < n ; i++){
solution[i] = _problem.solution[i];
}
fitness(_problem.fitness()); // copy the fitness
}
int& operator[] (unsigned i)
{
return solution[i];
}
void create(){ // create and initialize a solution
int random, temp;
for (int i=0; i< n; i++)
solution[i]=i;
// we want a random permutation so we shuffle
for (int i = 0; i < n; i++){
random = rand()%(n-i) + i;
temp = solution[i];
solution[i] = solution[random];
solution[random] = temp;
}
}
int evaluate() { // evaluate the solution
int cost=0;
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
cost += a[i][j] * b[solution[i]][solution[j]];
evalNb++;
//std::this_thread::sleep_for(std::chrono::milliseconds(1));
//std::cout << "Evaluation " << evalNb << std::endl;
return cost;
}
void printSolution() {
for (int i = 0; i < n ; i++)
std::cout << solution[i] << " " ;
std::cout << std::endl;
}
};
class IndiInit : public eoInit<Indi>
{
public:
void operator()(Indi & _problem)
{
_problem.create();
}
};
class IndiEvalFunc : public eoEvalFunc<Indi>
{
public:
void operator()(Indi & _problem)
{
_problem.fitness(_problem.evaluate());
}
};
class IndiXover : public eoQuadOp<Indi> {
public:
/* The two parameters in input are the parents.
The first parameter is also the output ie the child
*/
bool operator()(Indi & _problem1, Indi & _problem2)
{
int i;
int random, temp;
std::vector<int> unassigned_positions(n);
std::vector<int> remaining_items(n);
int j = 0;
/* 1) find the items assigned in different positions for the 2 parents */
for (i = 0 ; i < n ; i++){
if (_problem1.solution[i] != _problem2.solution[i]){
unassigned_positions[j] = i;
remaining_items[j] = _problem1.solution[i];
j++;
}
}
/* 2) shuffle the remaining items to ensure that remaining items
will be assigned at random positions */
for (i = 0; i < j; i++){
random = rand()%(j-i) + i;
temp = remaining_items[i];
remaining_items[i] = remaining_items[random];
remaining_items[random] = temp;
}
/* 3) copy the shuffled remaining items at unassigned positions */
for (i = 0; i < j ; i++)
_problem1.solution[unassigned_positions[i]] = remaining_items[i];
// crossover in our case is always possible
return true;
}
};
class IndiSwapMutation: public eoMonOp<Indi> {
public:
bool operator()(Indi& _problem) {
int i,j;
int temp;
// generate two different indices
i=rand()%n;
do
j = rand()%n;
while (i == j);
// swap
temp = _problem.solution[i];
_problem.solution[i] = _problem.solution[j];
_problem.solution[j] = temp;
return true;
}
};
void parseFile(eoParser & parser, parameters & param)
{
// For each parameter, you can in on single line
// define the parameter, read it through the parser, and assign it
param.seed = parser.createParam(unsigned(time(0)), "seed", "Random number seed", 'S').value(); // will be in default section General
// init and stop
param.loadName = parser.createParam(string(""), "Load","A save file to restart from",'L', "Persistence" ).value();
param.inst = parser.createParam(string(""), "inst","a dat file to read instances from",'i', "Persistence" ).value();
param.schema = parser.createParam(string(""), "schema","an xml file mapping process",'s', "Persistence" ).value();
param.popSize = parser.createParam(unsigned(10), "popSize", "Population size",'P', "Evolution engine" ).value();
param.tSize = parser.createParam(unsigned(2), "tSize", "Tournament size",'T', "Evolution Engine" ).value();
param.minGen = parser.createParam(unsigned(100), "minGen", "Minimum number of iterations",'g', "Stopping criterion" ).value();
param.maxGen = parser.createParam(unsigned(300), "maxGen", "Maximum number of iterations",'G', "Stopping criterion" ).value();
param.pCross = parser.createParam(double(0.6), "pCross", "Probability of Crossover", 'C', "Genetic Operators" ).value();
param.pMut = parser.createParam(double(0.1), "pMut", "Probability of Mutation", 'M', "Genetic Operators" ).value();
// the name of the "status" file where all actual parameter values will be saved
string str_status = parser.ProgramName() + ".status"; // default value
string statusName = parser.createParam(str_status, "status","Status file",'S', "Persistence" ).value();
// do the following AFTER ALL PARAMETERS HAVE BEEN PROCESSED
// i.e. in case you need parameters somewhere else, postpone these
if (parser.userNeedsHelp())
{
parser.printHelp(cout);
exit(1);
}
if (statusName != "")
{
ofstream os(statusName.c_str());
os << parser; // and you can use that file as parameter file
}
}
void loadInstances(const char* filename, int& n, int& bkv, int** & a, int** & b)
{
ifstream data_file;
int i, j;
data_file.open(filename);
if (! data_file.is_open())
{
cout << "\n Error while reading the file " << filename << ". Please check if it exists !" << endl;
exit (1);
}
data_file >> n;
data_file >> bkv; // best known value
// ****************** dynamic memory allocation ****************** /
a = new int* [n];
b = new int* [n];
for (i = 0; i < n; i++)
{
a[i] = new int[n];
b[i] = new int[n];
}
// ************** read flows and distanceMatrixs matrices ************** /
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
data_file >> a[i][j];
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
data_file >> b[i][j];
data_file.close();
}
#endif

27
trunk/smp/test/t-data.dat Executable file
View file

@ -0,0 +1,27 @@
12 224416
0 27 85 2 1 15 11 35 11 20 21 61
27 0 80 58 21 76 72 44 85 94 90 51
85 80 0 3 48 29 90 66 41 15 83 96
2 58 3 0 74 45 65 40 54 83 14 71
1 21 48 74 0 77 36 53 37 26 87 76
15 76 29 45 77 0 91 13 29 11 77 32
11 72 90 65 36 91 0 87 67 94 79 2
35 44 66 40 53 13 87 0 10 99 56 70
11 85 41 54 37 29 67 10 0 99 60 4
20 94 15 83 26 11 94 99 99 0 56 2
21 90 83 14 87 77 79 56 60 56 0 60
61 51 96 71 76 32 2 70 4 2 60 0
0 21 95 82 56 41 6 25 10 4 63 6
21 0 44 40 75 79 0 89 35 9 1 85
95 44 0 84 12 0 26 91 11 35 82 26
82 40 84 0 69 56 86 45 91 59 18 76
56 75 12 69 0 39 18 57 36 61 36 21
41 79 0 56 39 0 71 11 29 82 82 6
6 0 26 86 18 71 0 71 8 77 74 30
25 89 91 45 57 11 71 0 89 76 76 40
10 35 11 91 36 29 8 89 0 93 56 1
4 9 35 59 61 82 77 76 93 0 50 4
63 1 82 18 36 82 74 76 56 50 0 36
6 85 26 76 21 6 30 40 1 4 36 0

View file

@ -0,0 +1,72 @@
#include <MWModel.h>
#include <cassert>
#include <eo>
#include "smpTestClass.h"
using namespace paradiseo::smp;
using namespace std;
int main(void)
{
typedef struct {
unsigned popSize = 10;
unsigned tSize = 2;
double pCross = 0.8;
double pMut = 0.7;
unsigned maxGen = 1000;
} Param;
Param param;
rng.reseed(42);
loadInstances("t-data.dat", n, bkv, a, b);
// Evaluation function
IndiEvalFunc plainEval;
// Init a solution
IndiInit chromInit;
// Define selection
eoDetTournamentSelect<Indi> selectOne(param.tSize);
eoSelectPerc<Indi> select(selectOne);// by default rate==1
// Define operators for crossover and mutation
IndiXover Xover; // CROSSOVER
IndiSwapMutation mutationSwap; // MUTATION
// Encapsule in a tranform operator
eoSGATransform<Indi> transform(Xover, param.pCross, mutationSwap, param.pMut);
// Define replace operator
eoPlusReplacement<Indi> replace;
eoGenContinue<Indi> genCont(param.maxGen); // generation continuation
// Define population
eoPop<Indi> pop(param.popSize, chromInit);
try
{
MWModel<eoEasyEA,Indi> mw(genCont, plainEval, select, transform, replace);
mw.evaluate(pop);
std::cout << "Initial population :" << std::endl;
pop.sort();
std::cout << pop << std::endl;
mw(pop);
std::cout << "Final population :" << std::endl;
pop.sort();
std::cout << pop << std::endl;
}
catch(exception& e)
{
cout << "Exception: " << e.what() << '\n';
}
assert(pop.nth_element_fitness(0) == 229092);
return 0;
}

View file

@ -0,0 +1,104 @@
//-----------------------------------------------------------------------------
// BinaryPSO.cpp
//-----------------------------------------------------------------------------
//*
// An instance of a VERY simple Real-coded binary Particle Swarm Optimization Algorithm
//
//-----------------------------------------------------------------------------
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <eo>
#include <smp>
// Use functions from namespace std
using namespace std;
using namespace paradiseo::smp;
typedef eoMinimizingFitness FitT;
typedef eoBitParticle < FitT > Particle;
double binary_value (const Particle & _particle)
{
double sum = 0;
for (unsigned i = 0; i < _particle.size(); i++)
sum +=_particle[i];
return (sum);
}
int main(void)
{
const unsigned int SEED = 42; // seed for random number generator
const unsigned int MAX_GEN=500;
const unsigned int VEC_SIZE = 10;
const unsigned int POP_SIZE = 20;
const unsigned int NEIGHBORHOOD_SIZE= 3;
const double VELOCITY_INIT_MIN= -1;
const double VELOCITY_INIT_MAX= 1;
const double VELOCITY_MIN= -1.5;
const double VELOCITY_MAX= 1.5;
const double INERTIA= 1;
const double LEARNING_FACTOR1= 1.7;
const double LEARNING_FACTOR2= 2.3;
rng.reseed(SEED);
eoPop<Particle> pop;
eoEvalFuncPtr<Particle, double, const Particle& > eval(binary_value);
eoRingTopology<Particle> topology(NEIGHBORHOOD_SIZE);
eoUniformGenerator<bool> uGen;
eoInitFixedLength < Particle > random (VEC_SIZE, uGen);
pop.append (POP_SIZE, random);
eoUniformGenerator < double >sGen (VELOCITY_INIT_MIN, VELOCITY_INIT_MAX);
eoVelocityInitFixedLength < Particle > veloRandom (VEC_SIZE, sGen);
eoFirstIsBestInit < Particle > localInit;
eoInitializer <Particle> fullInit(eval,veloRandom,localInit,topology,pop);
fullInit();
pop.sort();
cout << "INITIAL POPULATION:" << endl;
for (unsigned i = 0; i < pop.size(); ++i)
cout << "\t best fit=" << pop[i] << endl;
eoRealVectorBounds bnds(VEC_SIZE,VELOCITY_MIN,VELOCITY_MAX);
eoStandardVelocity <Particle> velocity (topology,INERTIA,LEARNING_FACTOR1,LEARNING_FACTOR2,bnds);
eoSigBinaryFlight <Particle> flight;
eoGenContinue <Particle> genCont (MAX_GEN);
try
{
MWModel<eoEasyPSO, Particle> pso(genCont, eval, velocity, flight);
pso(pop);
pop.sort();
cout << "FINAL POPULATION:" << endl;
for (unsigned i = 0; i < pop.size(); ++i)
{
cout << "\t best fit=" << pop[i] << endl;
}
}
catch(exception& e)
{
cout << "Exception: " << e.what() << '\n';
}
return 0;
}
//-----------------------------------------------------------------------------

View file

@ -0,0 +1,172 @@
//-----------------------------------------------------------------------------
// BinaryPSO.cpp
//-----------------------------------------------------------------------------
//*
// An instance of a VERY simple Real-coded binary Particle Swarm Optimization Algorithm
//
//-----------------------------------------------------------------------------
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <eo>
#include <smp>
// Use functions from namespace std
using namespace std;
using namespace paradiseo::smp;
//-----------------------------------------------------------------------------
typedef eoMinimizingFitness FitT;
typedef eoBitParticle < FitT > Particle;
//-----------------------------------------------------------------------------
// EVALFUNC
//-----------------------------------------------------------------------------
// Just a simple function that takes binary value of a chromosome and sets
// the fitness
double binary_value (const Particle & _particle)
{
double sum = 0;
for (unsigned i = 0; i < _particle.size(); i++)
sum +=_particle[i];
return (sum);
}
int main(void)
{
// PARAMETRES
// all parameters are hard-coded!
const unsigned int SEED = 42; // seed for random number generator
const unsigned int MAX_GEN=50;
const unsigned int VEC_SIZE = 10;
const unsigned int POP_SIZE = 20;
const unsigned int NEIGHBORHOOD_SIZE= 3;
const double VELOCITY_INIT_MIN= -1;
const double VELOCITY_INIT_MAX= 1;
const double VELOCITY_MIN= -1.5;
const double VELOCITY_MAX= 1.5;
const double INERTIA= 1;
const double LEARNING_FACTOR1= 1.7;
const double LEARNING_FACTOR2= 2.3;
//////////////////////////
// RANDOM SEED
//////////////////////////
//reproducible random seed: if you don't change SEED above,
// you'll aways get the same result, NOT a random run
rng.reseed(SEED);
/// SWARM
// population <=> swarm
eoPop<Particle> pop;
/// EVALUATION
// Evaluation: from a plain C++ fn to an EvalFunc Object
eoEvalFuncPtr<Particle, double, const Particle& > eval( binary_value );
///////////////
/// TOPOLOGY
//////////////
// ring topology
eoRingTopology<Particle> topology(NEIGHBORHOOD_SIZE);
/////////////////////
// INITIALIZATION
////////////////////
// position initialization
eoUniformGenerator<bool> uGen;
eoInitFixedLength < Particle > random (VEC_SIZE, uGen);
pop.append (POP_SIZE, random);
// velocities initialization component
eoUniformGenerator < double >sGen (VELOCITY_INIT_MIN, VELOCITY_INIT_MAX);
eoVelocityInitFixedLength < Particle > veloRandom (VEC_SIZE, sGen);
// first best position initialization component
eoFirstIsBestInit < Particle > localInit;
// Create an eoInitialier that:
// - performs a first evaluation of the particles
// - initializes the velocities
// - the first best positions of each particle
// - setups the topology
eoInitializer <Particle> fullInit(eval,veloRandom,localInit,topology,pop);
// Full initialization here to be able to print the initial population
// Else: give the "init" component in the eoEasyPSO constructor
fullInit();
/////////////
// OUTPUT
////////////
// sort pop before printing it!
pop.sort();
// Print (sorted) the initial population (raw printout)
cout << "INITIAL POPULATION:" << endl;
for (unsigned i = 0; i < pop.size(); ++i)
cout << "\t best fit=" << pop[i] << endl;
///////////////
/// VELOCITY
//////////////
// Create the bounds for the velocity not go to far away
eoRealVectorBounds bnds(VEC_SIZE,VELOCITY_MIN,VELOCITY_MAX);
// the velocity itself that needs the topology and a few constants
eoStandardVelocity <Particle> velocity (topology,INERTIA,LEARNING_FACTOR1,LEARNING_FACTOR2,bnds);
///////////////
/// FLIGHT
//////////////
// Binary flight based on sigmoid function
eoSigBinaryFlight <Particle> flight;
////////////////////////
/// STOPPING CRITERIA
///////////////////////
// the algo will run for MAX_GEN iterations
eoGenContinue <Particle> genCont (MAX_GEN);
// GENERATION
/////////////////////////////////////////
// the algorithm
////////////////////////////////////////
// standard PSO requires
// stopping criteria, evaluation,velocity, flight
try
{
MWModel<eoSyncEasyPSO,Particle> pso(genCont, eval, velocity, flight);
// Apply the algo to the swarm - that's it!
pso(pop);
// OUTPUT
// Print (sorted) intial population
pop.sort();
cout << "FINAL POPULATION:" << endl;
for (unsigned i = 0; i < pop.size(); ++i)
cout << "\t best fit=" << pop[i] << endl;
}
catch(exception& e)
{
cout << "Exception: " << e.what() << '\n';
}
return 0;
}
//-----------------------------------------------------------------------------

View file

@ -0,0 +1,40 @@
#include <cassert>
#include <vector>
#include <cstdlib>
#include <smp>
#include <eo>
#include "smpTestClass.h"
using namespace std;
using namespace paradiseo::smp;
int main(void)
{
srand(time(NULL));
loadInstances("t-data.dat", n, bkv, a, b);
// Evaluation function
IndiEvalFunc plainEval;
// Init a solution
IndiInit chromInit;
eoPop<Indi> pop(100, chromInit);
int nbWorkers = 4;
Scheduler<Indi> sched(nbWorkers);
sched(plainEval, pop);
std::cout << pop << std::endl;
// All indi would be evaluate once
for( unsigned i = 0; i < pop.size(); i++)
assert(pop[i].evalNb == 1);
return 0;
}

View file

@ -0,0 +1,60 @@
#include <cassert>
#include <vector>
#include <atomic>
#include <smp>
#include "smpTestClass.h"
using namespace std;
using namespace paradiseo::smp;
void f(std::atomic<int> &x)
{
for(int i = 0; i < 100; i++) {
cout << x << endl;
x++;
}
}
void g(std::atomic<int> &x)
{
for(int i = 0; i < 100; i++)
x--;
}
void foo()
{
std::cout << "Foo" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main(void)
{
//---------------------------------------------------
std::atomic<int> nb(0);
Thread t1(&f,std::ref(nb));
Thread t2(&g,std::ref(nb));
t1.join();
t2.join();
assert(nb == 0); // Test atomic_barrier
//--------------------------------------------------
try
{
t1.start(foo);
t1.join();
}
catch(exception& e)
{
cout << "Exception: " << e.what() << '\n';
}
return 0;
}