c_cpp 遗伝的アルゴリズム
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 遗伝的アルゴリズム相关的知识,希望对你有一定的参考价值。
#include "./GA.hpp"
#include "./GeneticOperator.hpp"
int main(void)
{
GeneticOperator::init_random(1);
GA::TestRun();
return 0;
}
#ifndef __INDIVIDUAL_HEADER__
#define __INDIVIDUAL_HEADER__
#include <cmath>
#include <iostream>
#include <vector>
#include "./Gene.hpp"
#include "./GeneticOperator.hpp"
class Gene;
class Individual
{
public:
std::vector<Gene> genotype_; // a set of genes
double fitness_;
public:
Individual(void){}
Individual(std::size_t length, std::size_t value_max);
~Individual(void){}
// initialize genotype
void initGenotype(std::size_t chromosome_length, std::size_t gene_max);
// copy operation for individual
Individual& operator=(const Individual &copied);
// compare fitness of individuals
// if this individual's fittness is bigger than compared individual's
// this method returns true.
bool operator>(const Individual &compared) const;
// mutation
void mutate(void);
//----- accesser method -----//
std::vector<Gene> GetGenotype(void) const { return this->genotype_; }
void SetGenotype(const std::vector<Gene> &genotype) { this->genotype_ = genotype; }
std::size_t GetValue(int locus) { return this->genotype_[locus].GetValue(); }
void SetValue(int locus, int value) { this->genotype_[locus].SetValue(value); }
std::size_t length(void) const { return genotype_.size(); }
double GetFitness(void) const { return fitness_; }
void SetFitness(double fitness) { this->fitness_ = fitness; }
//----- information -----//
void print(void) const;
};
#endif // __INDIVIDUAL_HEADER__
#include "./individual.hpp"
#include <iomanip>
Individual::Individual(std::size_t length, std::size_t gene_max)
{
this->genotype_.resize(length);
for(auto &gene : this->genotype_) {
gene.SetMaxValue(gene_max);
}
this->fitness_ = 0;
}
void Individual::initGenotype
(std::size_t chromosome_length, std::size_t gene_max)
{
// initialize gene random value
this->genotype_.resize(chromosome_length);
for(auto &gene : genotype_) {
gene.SetMaxValue(gene_max);
gene.SetValue(GeneticOperator::rnd(gene.GetMaxValue()));
}
}
Individual& Individual::operator=(const Individual &copied)
{
this->genotype_ = copied.genotype_;
this->fitness_ = copied.fitness_;
return (*this);
}
bool Individual::operator>(const Individual &compared) const
{
if(this->fitness_ > compared.fitness_) {
return true;
} else {
return false;
}
}
void Individual::mutate(void)
{
for(auto &gene : genotype_) {
// conduct mutation
if( GeneticOperator::rnd() < GeneticOperator::mutation_rate ) {
gene.SetValue(GeneticOperator::rnd());
}
}
}
void Individual::print(void) const
{
for(auto gene : this->genotype_) {
std::cout << std::setw(2) << gene.GetValue() << ", ";
}
std::cout << this->fitness_ << std::endl;
}
#ifndef __GENETIC_OPERATOR_HEADER__
#define __GENETIC_OPERATOR_HEADER__
#include "./individual.hpp"
#include <random>
class Individual;
namespace GeneticOperator {
const double crossover_rate = 0.80;
const double mutation_rate = 0.50;
static std::mt19937 mt_engine;
// 個体indi1と個体indi2を入れ替える
void swap(Individual *ind1, Individual *indi2);
// 個体ind1と個体ind2の遺伝子座locusを入れ替える
void swap(Individual *ind1, Individual *ind2, std::size_t locus);
// 交叉オペレーション
// 親個体parent1, parent2 --> 子個体child1, child2
void one_point_crossover(const Individual& parent1, const Individual& parent2,
Individual* child1, Individual* child2);
void two_points_crossover(const Individual& parent1, const Individual& parent2,
Individual* child1, Individual* child2);
void uniform_crossover(const Individual& parent1, const Individual& parent2,
Individual* child1, Individual* child2);
// 選択オペレーション
void roulette_selection(const std::vector<Individual> &candidate,
std::vector<Individual> *selected, std::size_t nElite);
// 乱数生成
void init_random(std::size_t seed);
// generate [0, n-1] random number as integer
std::size_t rnd(std::size_t n);
// generate [min, max] random number as integer
std::size_t rnd(std::size_t min, std::size_t max);
// generate [0.0, 1.0] random number as double
double rnd(void);
// generate [min, max] random number as double
double rnd(double min, double max);
}
#endif // __GENETIC_OPERATOR_HEADER__
#include "./GeneticOperator.hpp"
#include "./individual.hpp"
void GeneticOperator::swap(Individual *ind1, Individual *ind2)
{
Individual tmp_ind;
tmp_ind = (*ind1);
(*ind1) = (*ind2);
(*ind2) = tmp_ind;
}
void GeneticOperator::swap(Individual *ind1, Individual *ind2, std::size_t locus)
{
std::swap(ind1->genotype_[locus], ind2->genotype_[locus]);
}
/*
* Crossover
*/
void GeneticOperator::one_point_crossover(
const Individual& parent1, const Individual& parent2,
Individual* child1, Individual* child2)
{
}
void GeneticOperator::two_points_crossover(
const Individual& parent1, const Individual& parent2,
Individual* child1, Individual* child2)
{
}
void GeneticOperator::uniform_crossover(
const Individual& parent1, const Individual& parent2,
Individual* child1, Individual* child2)
{
// check crossover probability
if( rnd() > crossover_rate ) {
return;
}
// copy parents to children
std::size_t length = parent1.length();
(*child1) = parent1;
(*child2) = parent2;
// conduct uniform crossover
for(std::size_t locus=0; locus<length; ++locus) {
if( rnd() < 0.50 ) {
GeneticOperator::swap(child1, child2, locus);
}
}
}
/*
* Selection
*/
void GeneticOperator::roulette_selection(const std::vector<Individual> &candidate,
std::vector<Individual> *selected, std::size_t nElite)
{
double sum_fitness, border, border_rate;
// calculate sum of fitness
sum_fitness = 0.0;
for(auto individual : candidate) {
sum_fitness += individual.GetFitness();
}
// spin roulette "rouletteTimes" times
int j;
for(std::size_t n=0; n<10; n++) {
border_rate = sum_fitness * GeneticOperator::rnd();
border = candidate[0].GetFitness();
j = 0;
while(border < border_rate) {
border += candidate[++j].GetFitness();
}
(*selected)[n] = candidate[j];
}
}
/*
* Random Generator
*/
void GeneticOperator::init_random(std::size_t seed)
{
mt_engine = std::mt19937(seed);
}
std::size_t GeneticOperator::rnd(std::size_t n)
{
std::uniform_int_distribution<int> dist(0, n);
return dist(mt_engine);
}
std::size_t GeneticOperator::rnd(std::size_t min, std::size_t max)
{
std::uniform_int_distribution<int> dist(min, max);
return dist(mt_engine);
}
double GeneticOperator::rnd(void)
{
std::uniform_real_distribution<double> dist(0.0, 1.0);
return dist(mt_engine);
}
double GeneticOperator::rnd(double min, double max)
{
std::uniform_real_distribution<double> dist(min, max);
return dist(mt_engine);
}
#ifndef __GENE_HEADER__
#define __GENE_HEADER__
#include <string>
class Gene {
private:
std::size_t value_;
std::size_t max_value_;
public:
Gene(void)
{
}
Gene(const std::size_t value)
: value_(value)
{
}
std::size_t GetValue(void)
{
return this->value_;
}
void SetValue(std::size_t value)
{
this->value_ = value;
}
std::size_t GetMaxValue(void)
{
return this->max_value_;
}
void SetMaxValue(std::size_t max_value)
{
this->max_value_ = max_value;
}
};
#endif
#ifndef __GA_HEADER__
#define __GA_HEADER__
#include "./Gene.hpp"
#include "./individual.hpp"
#include "./GeneticOperator.hpp"
#include <functional>
class GA
{
public:
typedef std::function<void(Individual, Individual,
Individual*, Individual*)> CrossoverFunc;
typedef std::function<void(const std::vector<Individual>&,
std::vector<Individual>*, std::size_t)> SelectionFunc;
typedef std::function<void(Individual*)> FitnessFunc;
enum CrossoverMethod {ONE_POINT, TWO_POINTS, UNIFORM};
enum SelectionMethod {ROULETTE, RANK, TOURNAMENT};
private:
std::vector<Individual> population_;
std::vector<Individual> parent_population_;
// Function Members
CrossoverFunc crossover;
SelectionFunc selection;
FitnessFunc calc_fitness;
public:
GA(void) {}
~GA(void) {}
// set functions
void selectCrossoverMethod(CrossoverMethod type);
void selectSelectionMethod(SelectionMethod type);
void SetFitnessFunction(FitnessFunc func) { calc_fitness = func; }
// initialize
void initializePopulation(std::size_t population_size,
std::size_t chromosome_length, std::size_t max_value);
// Generation Alternation
void SimpleGA(void);
// Calculate fitness
void CalcFitness(void);
// Progress(genotype and fitness value)
void Progress(void);
static void TestMethod(void);
static void TestRun(void);
static void TestFitnessFunction(Individual* ind)
{
double fitness;
// calc fitness
fitness = 0.0;
for(auto i=0; i<5; ++i) {
fitness += (10 - ind->genotype_[i].GetValue());
}
fitness /= 5;
ind->SetFitness(fitness);
}
};
#endif // __GA_HEADER__
#include "./Gene.hpp"
#include "./individual.hpp"
#include "./GeneticOperator.hpp"
#include "./GA.hpp"
void GA::selectCrossoverMethod(GA::CrossoverMethod type)
{
switch(type) {
case ONE_POINT:
break;
case TWO_POINTS:
break;
case UNIFORM:
crossover = GeneticOperator::uniform_crossover;
break;
default:
std::cerr << "select crossover function" << std::endl;
}
}
void GA::selectSelectionMethod(GA::SelectionMethod type)
{
switch(type) {
case ROULETTE:
selection = GeneticOperator::roulette_selection;
break;
case RANK:
break;
case TOURNAMENT:
break;
default:
std::cerr << "select selection function" << std::endl;
}
}
void GA::initializePopulation(std::size_t population_size,
std::size_t chromosome_length, std::size_t max_value)
{
this->population_.resize(population_size);
this->parent_population_.resize(population_size);
for(auto &individual : this->population_) {
individual.initGenotype(chromosome_length, max_value);
}
for(auto &individual : this->parent_population_) {
individual.initGenotype(chromosome_length, max_value);
}
}
void GA::SimpleGA(void)
{
Individual max_ind;
// ===== selection ===== //
selection(this->population_, &this->parent_population_, 0);
// ===== crossover ===== //
for(std::size_t ind=0; ind<population_.size(); ind+=2) {
crossover(this->parent_population_[ind], this->parent_population_[ind+1],
&this->population_[ind], &this->population_[ind+1]);
}
if(population_.size() % 2 != 0) {
this->population_[population_.size()-1]
= this->parent_population_[population_.size()-1];
}
// ===== conduct mutation ===== //
for(auto &individual : population_) {
individual.mutate();
}
// ===== calculate fitness for all individuals ===== //
this->CalcFitness();
}
// calculate fitness for all individuals
void GA::CalcFitness(void)
{
for(auto &individual : this->population_) {
calc_fitness(&individual);
}
}
void GA::Progress(void)
{
for(auto &individual : this->population_) {
individual.print();
}
}
void GA::TestMethod(void)
{
// initialize individual
Individual ind1(15, 20), ind2(15, 20);
ind1.initGenotype(15, 20);
ind2.initGenotype(15, 20);
std::cout << "========== Initial Individual ==========" << std::endl;
std::cout << "Individual 1: ";
ind1.print();
std::cout << "individual 2: ";
ind2.print();
// swap chromosome
GeneticOperator::swap(&ind1, &ind2);
std::cout << "========== After Swap ==========" << std::endl;
std::cout << "Individual 1: ";
ind1.print();
std::cout << "individual 2: ";
ind2.print();
// mutation
ind1.mutate();
ind2.mutate();
std::cout << "========== After Mutation ==========" << std::endl;
std::cout << "Individual 1: ";
ind1.print();
std::cout << "individual 2: ";
ind2.print();
// crossover
Individual child1, child2;
GeneticOperator::uniform_crossover(ind1, ind2, &child1, &child2);
std::cout << "========== After Uniform CrossOver ==========" << std::endl;
std::cout << "Individual 1: ";
ind1.print();
std::cout << "individual 2: ";
ind2.print();
std::cout << "child 1: ";
child1.print();
std::cout << "child 2: ";
child2.print();
}
void GA::TestRun(void)
{
GA ga;
// population size: 10
// chromosome length: 5
// value max: 10
ga.initializePopulation(10, 5, 10);
ga.selectCrossoverMethod(GA::UNIFORM);
ga.selectSelectionMethod(GA::ROULETTE);
ga.SetFitnessFunction(TestFitnessFunction);
ga.CalcFitness();
for(int i=0; i<30; ++i) {
std::cout << "generation time: " << i << std::endl;
ga.SimpleGA();
ga.Progress();
std::cin.get();
};
}
以上是关于c_cpp 遗伝的アルゴリズム的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp 插入ソート,バブルソート,クイックソートの各种アルゴリズムソースコード(计测用主关数も付属)