⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ga.cpp

📁 该源码是一个用c++编写的经典的遗传算法
💻 CPP
字号:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#include <iostream>
#include <ctype.h>
#include <cstdlib>

using namespace std;

//用于改变随机二进制位种子iseed的常量
#define IB1 1
#define IB2 2
#define IB5 16
#define IB18 131072L
#define MASK (IB1+IB2+IB5)

//以下常量用于随机数发生器,IA1,IQ1,IR1有三组数可供选择,取决于FPGA易实现性和资源最小化
#define IM1 2147483647L
#define AM1 (1.0/IM1)
#define IA1 16807L
#define IQ1 127773L
#define IR1 2836L

//#define IA1 48271L
//#define IQ1 44488L
//#define IR1 3399L

//#define IA1 69621L
//#define IQ1 30845L
//#define IR1 23902L


//idum为浮点随机数种子,iseed为产生随机二进制位的种子,seed为初始种子
static long idum=0;
static unsigned long iseed;
static unsigned long seed=0;



struct SGenome
{
unsigned char **data;          //data指向一个二维数组,data[种群数][每个基因的染色体数]
double *score, *psum;          //score为每个基因的评估值,psum为每个基因的加权和
unsigned int size, width;      //size是种群数大小,width为每个基因的染色体数
double max_score, min_score, ave_score;  //分别是当前种群评估值的最大、最小和平均值
};


//产生浮点随机数的函数,该函数能保证产生的随机数是均匀的
double garan2()
{
long k;
double temp;

  k=(idum)/IQ1;
  idum=IA1*(idum-k*IQ1)-k*IR1;
  if (idum < 0) idum += IM1;

  temp = AM1*idum;
  return temp;
}

double GARandomFloat()
{
double val;	
	val = garan2();
	return val;
}


//在low和high之间产生一个整型随机数的函数
int GARandomInt(int low, int high)
{ 
double val;

  val = (double)high-(double)low+(double)1; 
  val*=garan2(); 
  return ((int)val+low);
}


//随机产生一个0或1的函数
int GARandomBit()
{
  if (iseed & IB18)
  {
    iseed=((iseed ^ MASK) << 1) | IB1;
    return 1;
  }
  else
  {
    iseed <<= 1;
    return 0;
  }
}


//设置随机数初始种子seed的值函数,这里用机器当前时间做种子,而在FPGA硬件实现时没有机器时间,
//能否用硬件设计一个时钟计数器(16位或32位),然后随机取计算器的制作为初始种子。或者考虑用其它更好的办法。

void GARandomSeed()
{
unsigned long int tmp;

    while(seed == 0)
	{
      tmp = time(NULL);
      for(unsigned int i=0; i < 8*sizeof(unsigned int); i++)
	     seed += (tmp & (1 << i));
    }

    idum = (long)seed;
    if (idum == 0) idum=1;
    if (idum < 0) idum = -idum;

    iseed = seed;
}


//由指定概率确定0,1翻转的函数
bool GAFlipCoin(double p)
{
  return((p == 1.0) ? true : (p == 0.0) ? false : ((GARandomFloat() <= p) ? true : false));
}


//目标函数,这里假设最优的染色体已知(放在buf里),实际应该根据滤波器的频率响应来确定评估值,目前评估方法还没有想好,你有没有好多想法?
double objFunction1(unsigned char *p, unsigned int n)
{
double score=0.0;
unsigned int buf[24] = {1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0};
unsigned int i;

    for (i=0; i < n; i++)
	{
        if (p[i] == buf[i])
	      score += 1.0;
	}

	return score;
}

//计算种群每个染色体的目标函数值
void evaluate(SGenome &s_pop)
{
double score=0.0, sum=0.0;
unsigned int i;

    for(i=0; i < s_pop.size; i++)
	{
		score = objFunction1(s_pop.data[i], s_pop.width);
		s_pop.score[i] = score;
		sum += score;
		if (i == 0)
		{
			s_pop.max_score = score;
			s_pop.min_score = score;
		}
		else
		{
            if (s_pop.max_score < score)
				s_pop.max_score = score;
			if (s_pop.min_score > score)
				s_pop.min_score = score;
		}
	}

	s_pop.ave_score = sum / s_pop.size;
}

//打印结果
void printScore(SGenome &s_pop)
{
unsigned int i, j;

    for (i=0; i < s_pop.size; i++)
	{
	    for (j=0; j < s_pop.width; j++)
	        cout << (int)s_pop.data[i][j] << "/ ";
	    cout << endl;
	}

    for (i=0; i < s_pop.size; i++)
	    cout << s_pop.score[i] << " ";
	cout << endl;
}


//采用冒泡排序对染色体根据评估值进行排序,这里要改用和谐理论排序算法来实现
void sortPop(SGenome &s_pop)
{
unsigned int i,j;
unsigned char *tmpdata = new unsigned char[s_pop.width];
double tmpfit;

    for (i= 1; i < s_pop.size; i++)
		for (j=0; j < s_pop.size-i; j++)
		{
			if (s_pop.score[j] < s_pop.score[j+1])
			{
				tmpfit = s_pop.score[j];
                memcpy(tmpdata, s_pop.data[j], s_pop.width*sizeof(unsigned char));
				s_pop.score[j] = s_pop.score[j+1];
                memcpy(s_pop.data[j], s_pop.data[j+1], s_pop.width*sizeof(unsigned char));
				s_pop.score[j+1] = tmpfit;
                memcpy(s_pop.data[j+1], tmpdata, s_pop.width*sizeof(unsigned char));
			}
		}

    delete [] tmpdata;
}


//预选择模块
void preSelect(SGenome &s_pop)
{
unsigned int i;


	if (s_pop.max_score == s_pop.min_score)
    {
	    for (i=0; i < s_pop.size; i++)
	  	    s_pop.psum[i] = (i+1)/(double)s_pop.size;
	}
    else
	{
        sortPop(s_pop);
	    s_pop.psum[0] = s_pop.score[0];
	    for (i=1; i < s_pop.size; i++)
	  	    s_pop.psum[i] = s_pop.score[i]+s_pop.psum[i-1];
		for (i=0; i < s_pop.size; i++)
		    s_pop.psum[i] /= s_pop.psum[s_pop.size-1];
	}
}

//选择模块,采用轮盘赌原则,返回的是染色体的序号
int select(double *psum, int n)
{
double cutoff;
int i, lower, upper;

      cutoff = GARandomFloat();
      lower = 0;
	  upper = n-1;
      while(upper >= lower)
	  {
          i = lower + (upper-lower)/2;
          if(psum[i] > cutoff)
              upper = i-1;
          else
              lower = i+1;
	  }
      lower = n-1 < lower ? n-1 : lower;
      lower = 0 > lower ? 0 : lower;

	  return lower;
}

//交叉模块,p1,p2为待交叉的两个染色体,c1,c2为交叉后生成的染色体,n为染色体含基因的个数
void crossOver(const unsigned char *p1, const unsigned char *p2, unsigned char* c1, unsigned char* c2, int n)
{
unsigned int momsite, momlen;
unsigned int dadsite, dadlen;

      momsite = dadsite = GARandomInt(0, n);
      momlen = dadlen = n - momsite;

      memcpy(c1, p1, momsite*sizeof(unsigned char));
      memcpy(c1+momsite, p2+dadsite, dadlen*sizeof(unsigned char));

      memcpy(c2, p2, dadsite*sizeof(unsigned char));
      memcpy(c2+dadsite, p1+momsite, momlen*sizeof(unsigned char));
}

//变异模块,p指向染色体,n为染色体含基因的个数,pmut为变异概率
void mutate(unsigned char *p, int n, double pmut)
{
int i, j;
double nmut;

    nmut = pmut * n;
    if (nmut < 1.0)
	{		// we have to do a flip test on each bit
        for (i=n-1; i >= 0; i--)
		{
            if(GAFlipCoin(pmut))
			{
                if (p[i] == 0)
	               p[i] = 1;
		        else
			       p[i] = 0;
			}
		}
	}
    else
	{				// only flip the number of bits we need to flip
        for(j=0; j<nmut; j++)
		{
           i = GARandomInt(0, n-1); // the index of the bit to flip
           if (p[i] == 0)
	          p[i] = 1;
		   else
		      p[i] = 0;
		}
	}
}

//返回最佳染色体的下标值,这里可以用和谐理论排序算法,一个时钟即可
double bestGenome(SGenome &s_pop)
{
double best = s_pop.score[0];
unsigned int index = 0;

	for (unsigned int i=1; i < s_pop.size; i++)
		if (best < s_pop.score[i])
		{
			best = s_pop.score[i];
			index = i;
		}

    return index;
}

//返回最差染色体的下标值,这里可以用和谐理论排序算法,一个时钟即可
unsigned int worstGenome(SGenome &s_pop)
{
double worst = s_pop.score[0];
unsigned int index = 0;

	for (unsigned int i=1; i < s_pop.size; i++)
		if (worst > s_pop.score[i])
		{
			worst = s_pop.score[i];
			index = i;
		}

    return index;
}

//对种群初始化
void initialize(SGenome &s_pop, int psize, int gwidth)
{
	s_pop.size = psize;
	s_pop.width = gwidth;
	s_pop.score = new double [psize];
	s_pop.psum = new double[psize];

    s_pop.data = new unsigned char * [psize];
    for (int i=0; i < psize; i++)
	{
        s_pop.data[i] = new unsigned char[gwidth];
        for(int j=0; j < gwidth; j++)
	        s_pop.data[i][j] = GARandomBit();
	}
}

//释放内存
void release(SGenome &s_pop)
{
unsigned int i;

    delete [] s_pop.score;
	delete [] s_pop.psum;

	for (i=0; i < s_pop.size; i++)
		delete [] s_pop.data[i];

	delete [] s_pop.data;
}

void main()
{
SGenome  pop, new_pop;
unsigned int i;
unsigned int gen_no, sel_no, mom, dad;
unsigned int width = 24;      //基因个数
unsigned int popsize = 100;    //种群所含的染色体数,选为10,便于用和谐理论排序算法
unsigned int ngen = 100;      //最大叠代次数
double pmut = 0.001;          //变异概率
double pcross = 0.9;          //交叉概率
unsigned int old_best, new_best;

    cout << "This program tries to len a binary pattern\n\n";

    GARandomSeed();

//initialize
	initialize(pop, popsize, width);
    initialize(new_pop, popsize, width);

//evaluate
	evaluate(pop);
	printScore(pop);


//evolve
  gen_no = 0;
  while (gen_no++ < ngen)
  {
	  preSelect(pop);   //排序
	  for (sel_no = 0; sel_no < pop.size-1; sel_no += 2)
	  {
//select,每次选择两个染色体
		  mom = select(pop.psum, popsize);
		  dad = select(pop.psum, popsize);

//crossover,进行交叉
		  if(GAFlipCoin(pcross))
		  {
              crossOver(pop.data[mom], pop.data[dad], new_pop.data[sel_no], new_pop.data[sel_no+1], pop.width);
		  }
          else
		  {
              memcpy(new_pop.data[sel_no], pop.data[mom], pop.width*sizeof(unsigned char));   //直接将父辈拷给子辈
              memcpy(new_pop.data[sel_no+1], pop.data[dad], pop.width*sizeof(unsigned char));
		  }
//mutate,对子辈种群进行变异
		  mutate(new_pop.data[sel_no], new_pop.width, pmut);
		  mutate(new_pop.data[sel_no+1], new_pop.width, pmut);
	  }

	  new_best = bestGenome(new_pop);
	  old_best = bestGenome(pop);   	  
//replace new worst with old best,若子辈的最佳不如父辈的最佳,则用父辈的最佳替换子辈的最差,这一机制很重要,可以用和谐理论排序算法实现
	  if (pop.score[old_best] > new_pop.score[new_best])
          memcpy(new_pop.data[worstGenome(new_pop)], pop.data[old_best], pop.width*sizeof(unsigned char));

//current new_pop is the pop for next generation,子辈又是下一代的父辈
	  for (i=0; i < pop.size; i++)
          memcpy(pop.data[i], new_pop.data[i], pop.width*sizeof(unsigned char));
//evaluate,计算评估函数
      evaluate(pop);
  }


  printScore(pop);

  for (i=0; i < pop.width; i++)
	  cout << (int)pop.data[new_best][i];
  cout << endl;

  release(pop);
  release(new_pop);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -