I am trying to engineer a library for the Genetic Algorithm optimization method.
The main class for the GA is quite general. Here is what I have for it
struct GAOptions{
size_t max_ga_steps;
double weight;// -1 gives the maximum while +1 gives the minimum
double cxpb;
double mutpb;
};
template<class INDIVIDUAL>
INDIVIDUAL GeneticAlgorithm(
const GAOptions opt)
{
using Population = std::vector<INDIVIDUAL>;
Population population = INDIVIDUAL::generatePopulation();
int population_size = population.size();
for(auto &ind: population){
ind.updateFitness();
}
std::sort(begin(population), end(population),
[&opt](auto &a, auto& b){ return opt.weight*a.getFitness() < opt.weight*b.getFitness(); });
double prev{std::numeric_limits<double>::infinity()};
INDIVIDUAL prev;
INDIVIDUAL current = population[0];
int ga_steps{};
while(!INDIVIDUAL::fittestFound(current, prev) &&
ga_steps < opt.max_ga_steps){
ga_steps++;
// Perform elitism. Take xx% of the best
Population offspring;
int s = (5*population.size())/100;
offspring.insert(begin(offspring), begin(population), begin(population) + s);
// Inject new blood, xx% new population
s = (10*population.size())/100;
for(int i = 0; i < s; i++) {
offspring.push_back(
INDIVIDUAL::create()
);
}
// Mate the top 50% of the population
for(auto i = offspring.size(); i < population.size(); i++){
int m = rand()%(population.size()/2);
int f = rand()%(population.size()/2);
INDIVIDUAL child = population[m].mate(population[f], cxpb);
offspring.push_back(child);
}
for(auto& child: offspring){
if(static_cast<double>(rand())/RAND_MAX < mutpb){
child.mutate(0.1);
}
}
for(auto &ind:offspring){
ind.updateFitness();
}
population = offspring;
prev = current;
std::sort(begin(population), end(population),
[&weight](auto &a, auto& b){ return weight*a.getFitness() < weight*b.getFitness(); });
current = population[0];
}
INDIVIDUAL best = population[0];
return best;
}
As you can see there are a few requirements on the INDIVIDUAL template parameter. Aside from the member functions there are three static functions that need to be implemented.
The problem I am having is that static functions are not as flexible as I want them to be. For instance if the INDIVIDUAL class needs to know some info regarding how to create itself, that can not be passed to static method and since it is a static method it can not be part of the object.
Lets say I have an Individual class where the constructor needs three values in order to be able to create an object. The static create method is not going to be able to handle this.
How do I get around this issue?
One thought from me is to use std::function
for the three static methods as part of GAOptions
and remove the static functions from the INDIVIDUAL. This way I can use lambda expression to sort of bundle the info I need.
Any thoughts are appreciated. Please let me know if I should clear up something.
GAOptions
into something likestd::char_traits
, and have it templated overINDIVIDUAL
andGA_TRAITS