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 A *アルゴリズム

c_cpp 插入ソート,バブルソート,クイックソートの各种アルゴリズムソースコード(计测用主关数も付属)

python アルゴリズムクイックリファレンス:选択ソート

python アルゴリズムクイックリファレンス:插入ソート

python アルゴリズムクイックリファレンス:中央値ソート

python アルゴリズムクイックリファレンス:クイックソート