我正在尝试使用用C ++编写的MIT库GAlib在OpenMPI中运行一个非常简单的并行遗传算法。目前,我只是在每个核心上运行稳态遗传算法。但是,我还想在核心之间交换信息,即一些迁移的个体。我基本上试图在库外复制一个更简单的GADemeGA。尽管如此,虽然MPI发送/接收功能可以正常工作,但我无法用新的功能替换人口中的个人。所以我的问题是,是否有一种简单的方法可以简单地用不同的人替换一个人。我试图使用GAPopulation.C中的“替换”函数(在GAlib中),但在编译程序时遇到以下错误:
styblinski_tang_PA.cpp:208: error: no matching function for call to ‘GAPopulation::replace(GARealGenome&, GARealGenome&) const’
../../galib247/ga/GAPopulation.h:172: note: candidates are: GAGenome* GAPopulation::replace(GAGenome*, int, GAPopulation::SortBasis)
../../galib247/ga/GAPopulation.h:173: note: GAGenome* GAPopulation::replace(GAGenome*, GAGenome*)
通过创建整个群体的本地副本,修改它(实际上只是迁移的个体)然后将其输入遗传算法,解决了这个问题。
我现在将包含简单的makefile和代码。提前感谢您的帮助!
生成文件:
LIB =libga.a
MKDEPEND = makedepend
RM = rm -rf
CXX = mpic++
CXXFLAGS = -g -Wall
LD = mpic++ -w
AR = ar rv
# Set these paths to the location of the GA library and headers.
GA_INC_DIR= ../../galib247
GA_LIB_DIR= ../../galib247/ga
INC_DIRS= -I$(GA_INC_DIR)
LIB_DIRS= -L$(GA_LIB_DIR)
EXS= styblinski_tang_PA
.SUFFIXES: .cpp
.cpp.o:
$(CXX) $(CXXFLAGS) $(INC_DIRS) -lm -c $<
all: $(EXS)
# Use this for gnu make
$(EXS): %: %.o
$(CXX) $@.o -o $@ $(LIB_DIRS) -lga -lm
clean:
$(RM) $(EXS)
$(RM) *.o *~ *.bak *.pixie core
$(RM) *.dat
$(RM) ../common_files/best_individual?.dat
$(RM) *.out *.exe vc* *.pdb
计划:styblinski_tangPA.cpp:
#include <string>
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <ga/std_stream.h>
#include <ga/GASStateGA.h>
#include <mpi.h> // Necessary for running the code in parallel
#define INSTANTIATE_REAL_GENOME
#include <ga/GARealGenome.h>
using namespace std;
#define MIN_VALUE -5
#define MAX_VALUE 5
#define INC 0.01
#define DIM 4 // Dimensions of search space
float Objective(GAGenome& ); // Declaration of the objective function.
// The definition comes later in the file.
int main(int argc, char **argv){
// Initialize the MPI environment
MPI_Init(&argc, &argv);
// Get the number of processes
int mpi_tasks;
MPI_Comm_size(MPI_COMM_WORLD, &mpi_tasks);
// Get the rank of the process
int mpi_rank;
string rank;
ostringstream convert;
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
convert << mpi_rank;
rank = convert.str();
// Get the name of the processor
char processor_name[MPI_MAX_PROCESSOR_NAME];
int name_len;
MPI_Get_processor_name(processor_name, &name_len);
// Termination parameters:
int ngen = 200; // Total number of generations for termination
int popsize = 10; // Generation size
//int npop = 8; // Number of populations
int nmigr = 5; // Number of migrating individuals
//int ncon = 40; // no. generations the code looks back for
// convergence for
//int pcon = 1.0e-02; // Threshold value for convergence
ofstream outfile; // Initialising the output stream
ofstream imm; // Initialising the output stream for immigrants
// At the moment, the master node is not used other than for communications
if (mpi_rank !=0) {
// Calculating the population size for each core:
// popsize = popsize/ (mpi_tasks-1); //note that it will remain an integer
// In fact, as each population is run on a separate core, popsize is the
// size of each population.
// Setting real alleles (bounds) type:
GARealAlleleSet alleles(MIN_VALUE,MAX_VALUE); //Continuous, bounded variables
//GARealAlleleSet alleles(MIN_VALUE,MAX_VALUE); //Discrete, bounded variables
/* NB: The set of discrete alleles in fact increases in size because of the
mutator and crossover types used with real variables - bug! */
// Creating a genome of real numbers (1D array):
GARealGenome genome(DIM, alleles, Objective);
/* Description: GARealGenome( int length of array, float alleles (bounds,
either continuous or discrete), float objective function) */
GAPopulation swappop(genome,popsize);
// Setting the type of mutator:
genome.mutator(GARealGaussianMutator);
//genome.mutator(GARealUniformMutator);
//genome.mutator(GARealSwapMutator);
// Creating the genetic algorithm and setting its parameters:
GASteadyStateGA ga(genome); // Steady state genetic algorithm
// Setting the terminator conditions: either due to convergence or by no.
// generations (default):
//ga.terminator(GAGeneticAlgorithm::TerminateUponGeneration); //default
//ga.terminator(GAGeneticAlgorithm::TerminateUponConvergence); //alternative
//ga.terminator(GAGeneticAlgorithm::TerminateUponPopConvergence);
ga.minimize(); // Minimization problem
ga.populationSize(popsize);
ga.nGenerations(ngen); // When TerminateUponGeneration
//ga.nConvergence(ncon); // When TerminateUponConvergence or
//ga.pConvergence(pcon); // TerminateUponPopConvergence
// Setting the type of cross-over:
ga.crossover(GARealArithmeticCrossover);
//ga.crossover(GARealBlendCrossover);
// The following options are not advised:
//ga.crossover(GARealUniformCrossover);
//ga.crossover(GARealEvenOddCrossover);
//ga.crossover(GARealOnePointCrossover);
//ga.crossover(GARealTwoPointCrossover);
//ga.crossover(GARealPartialMatchCrossover);
//ga.crossover(GARealOrderCrossover);
//ga.crossover(GARealCycleCrossover);
// Setting the variables for the mutation and crossover probabilities:
ga.pMutation(0.05); // likelihood of mutating new offspring
ga.pCrossover(0.9); // likelihood of crossing over parents
// Specifying settings for calculating the fitness function:
ga.scoreFilename("generation.dat"); // name of output file for scores
ga.scoreFrequency(1); // keep the scores of every generation
ga.flushFrequency(1); // specify how often to write the score
// to disk
ga.selectScores(GAStatistics::AllScores); /* writing out average, maximum,
minimum, standard deviation and
divergence values of the fitness
function for later plotting. */
// Initializing the genetic algorithm:
ga.initialize();
// Output the initial population to file:
int counter=0;
string pop_evo ="pop_evolution"+rank+".dat";
outfile.open(pop_evo.c_str());
for(int ii=0; ii<ga.population().size(); ii++){
genome = ga.population().individual(ii);
outfile << counter << "\t";
for(int a=0; a<DIM; a++){
outfile << genome.gene(a) << "\t";
}
outfile << genome.score() << "\n";
}
float emigrant [nmigr][DIM];
float immigrant [nmigr][DIM];
string immigrants ="immigrants"+rank+".dat";
imm.open(immigrants.c_str());
// Running the algorithm until the termination condition is met:
while(!ga.done()) {
counter++;
//ga.step();
swappop = ga.population();
/* Migration - stepping stone approach, i.e. individuals are swapped
between neighbouring populations. The best individuals of one
population are copied across to the next one in stead of the worst
performing ones:*/
for (int i=0;i<nmigr;i++){
genome = ga.population().individual(i);
for (int j=0;j<nmigr;j++){
emigrant[i][j] = genome.gene(j);
}
}
// The following if-loops are required to avoid dead-lock
if (mpi_rank == (mpi_tasks-1)){
MPI_Send(&emigrant, (nmigr*DIM), MPI_FLOAT, 1, 1, MPI_COMM_WORLD);
MPI_Recv(&immigrant, (nmigr*DIM), MPI_FLOAT, (mpi_rank-1), mpi_rank,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
else if (mpi_rank == 1){
MPI_Send(&emigrant, (nmigr*DIM), MPI_FLOAT, (mpi_rank+1), (mpi_rank+1),
MPI_COMM_WORLD);
MPI_Recv(&immigrant, (nmigr*DIM), MPI_FLOAT, (mpi_tasks-1), 1,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
else {
MPI_Send(&emigrant, (nmigr*DIM), MPI_FLOAT, (mpi_rank+1), (mpi_rank+1),
MPI_COMM_WORLD);
MPI_Recv(&immigrant, (nmigr*DIM), MPI_FLOAT, (mpi_rank-1), mpi_rank,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
//MPI_Barrier(MPI_COMM_WORLD);
for (int i=0;i<nmigr;i++){
imm << counter << "\t" << i;
genome = swappop.individual((popsize-1)-i);
for (int j=0;j<DIM;j++){
genome.gene(j,immigrant[i][j]); //substituting the last (worst)
//individuals with the best ones of
//another population
//imm << "\t" << immigrant[i][j];
imm << "\t" << genome.gene(j);
}
//ga.population();
//imm << "\n" << ga.population().individual((popsize-1)-i);
imm << "\n";
}
ga.population(swappop);
ga.step();
// Printing the population to file for each generation for later plotting:
for(int ii=0; ii<popsize; ii++){
genome = ga.population().individual(ii);
outfile << counter << "\t";
for(int a=0; a<DIM; a++){
outfile << genome.gene(a) << "\t";
}
outfile << genome.score() << "\n";
}
}
imm.close(); // Closing the output file stream
outfile.close(); // Closing the output file stream
float best_individual [DIM];
float best_score;
for(int b=0; b<DIM; b++){
genome = ga.statistics().bestIndividual();
best_individual[b] = genome.gene(b);
best_score = genome.score();
}
// Printing out the best genome that the GA found for the current population
// to file:
string best_val = "../common_files/best_individual" + rank + ".dat";
outfile.open(best_val.c_str());
outfile << ga.statistics().bestIndividual() << "\n";
outfile << ga.statistics().bestIndividual().score() << "\n";
outfile.close(); //closing the output file stream
MPI_Send(&best_individual, DIM, MPI_FLOAT, 0, 0, MPI_COMM_WORLD);
MPI_Send(&best_score, 1, MPI_FLOAT, 0, 1, MPI_COMM_WORLD);
}
float individual [(mpi_tasks-1)][DIM];
float score [(mpi_tasks-1)];
if (mpi_rank==0){
for (int i=0; i<(mpi_tasks-1); i++){
MPI_Recv(&individual[i], DIM, MPI_FLOAT, (i+1), 0, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
MPI_Recv(&score[i], 1, MPI_FLOAT, (i+1), 1, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
cout << "\nBest individual population" << (i+1) << ":\n";
for(int j=0; j<DIM; j++){cout << individual[i][j] << "\t";}
cout << score[i] << "\n";
}
}
MPI_Barrier(MPI_COMM_WORLD);
if (mpi_rank==0){
// Initialising the value for the minimum:
float minimum = score[0];
int pop = 0;
for (int i=1; i<(mpi_tasks-1); i++){
// Selecting the actual minimum:
if (minimum>=score[i]){minimum=score[i]; pop=i;}
}
/*Printing the data to a file as well so that it can be used as the
starting point by the Nelder-Mead Simplex method in the hybrid
optimization technique.*/
outfile.open("../common_files/best_individual.dat");
for (int j=0; j<DIM; j++) {outfile << individual[pop][j] << "\t";}
outfile << "\nBest score: " << minimum;
outfile << "\nBelonging to population " << (pop+1);
outfile.close(); // Closing the output file stream*/
}
// Finalize the MPI environment.
MPI_Finalize();
return 0;
}
float Objective(GAGenome& g) { // Definition of the objective function
GARealGenome & genome = (GARealGenome &)g;
float y = 0; // Defining Styblinski–Tang function
for(int b=0; b<DIM; b++){
float sum;
sum = pow(genome.gene(b),4);
sum += - 16 * genome.gene(b) * genome.gene(b) + 5 * genome.gene(b);
y += sum;
}
return y;
}
运行命令:
make
mpirun -np 4 styblinski_tangPA
注意:将makefile中的目录更改为指向GAlib的位置。将styblinski_tangPA.cpp中输出文件的目录更改为所需位置。 编译时需要:OpenMPI或等效的GAlib。