遗传算法上机系列之用遗传算法求函数最值问题(附自己写的代码)

本文基于下面的最值问题进行求解:
  m a x f ( x 1 , x 2 ) = 21.5 + x 1 s i n ( 4 π x 1 ) + x 2 s i n ( 20 π x 2 ) \ max f(x_1,x_2)=21.5+x_1sin(4\pi x_1)+x_2sin(20\pi x_2)  maxf(x1,x2)=21.5+x1sin(4πx1)+x2sin(20πx2)
  − 3.0 ≤ x 1 ≤ 12.1 \ -3.0\le x_1\le 12.1  3.0x112.1
  4.1 ≤ x 2 ≤ 5.8 \ 4.1\le x_2\le 5.8  4.1x25.8
精度要求 ϵ = 1 0 − 4 \epsilon=10^{-4} ϵ=104

遗传算法的基本步骤

step1:按某种编码方式产生初始种群   p ( 0 ) \ p(0)  p(0),设种群代数   t = 0 \ t=0  t=0

常用编码方式:

二进制编码、实数编码、整数编码、排列编码、有限状态机编码、树编码……(本例中我们采用二进制编码,需要对应解码)

二进制编码

  x ∈ [ a , b ] \ x \in[a,b]  x[a,b],精度要求不小于   1 0 − α \ 10^{-\alpha}  10α.
编码公式:   2 m − 1 − 1 < ( b − a ) ∗ 1 0 α ≤ 2 m − 1 \ 2^{m-1}-1<(b-a)*10^\alpha\le2^{m-1}  2m11<(ba)10α2m1,根据取值范围即可求出共需要多少位二进制数才能满足精度要求
解码公式:   y = a + ( b − a ) ∗ x 2 m − 1 \ y=a+(b-a)*\frac{x}{2^m-1}  y=a+(ba)2m1x(其中   x \ x  x为无符号二进制换算成十进制之后的值)

本例中,按照精度要求及取值范围,   x 1 \ x_1  x1需要18位二进制编码,   x 2 \ x_2  x2需要15位二进制编码。
以下为初始化部分代码:

//初始化种群
void init()
{
	double p=0.5;
	//srand(time(0));
	for(int i=0;iRAND_MAX/2)
				s.append("1");
			else
				s.append("0");
		}
		pop.push_back(s);
	}
}

step2:计算种群   p ( t ) \ p(t)  p(t)中每个个体的适应度值

即按照解码公式进行解码之后带入函数中计算   f ( x 1 , x 2 ) \ f(x_1,x_2)  f(x1,x2)的值,即为本例的适应度值。相关代码如下(individual为自定义结构体,包含当前计算个体对应的   x 1 , x 2 , f \ x_1,x_2,f  x1,x2,f三个值:

//计算适应度值
individual Fitness(string s)
{
	individual T;
	double x1a = -3.0;
	double x1b = 12.1;
	double x2a = 4.1;
	double x2b = 5.8;
	string s1 = s.substr(0,18);
	string s2 = s.substr(18,15);
	int t1 = Transform(s1);
	int t2 = Transform(s2);
	T.x1 = x1a+(x1b-x1a)*t1/(pow(2.0,18)-1);
	T.x2 = x2a+(x2b-x2a)*t2/(pow(2.0,15)-1);
	T.fit = 21.5+T.x1*sin(4*PI*T.x1) +T.x2*sin(20*PI*T.x2);
	return T;
}

step3:按某种规则   p ( t ) \ p(t)  p(t)中选择一个子群体   p ′ ( t ) \ p'(t)  p(t)作为产生后代的父母,用交叉算子作用于   p ′ ( t ) \ p'(t)  p(t)产生交叉后代集合   O ′ ( t ) \ O'(t)  O(t),再用变异算子作用于   O ′ ( t ) \ O'(t)  O(t)产生变异后代集合   O ( t ) \ O(t)  O(t),计算   O ( t ) \ O(t)  O(t)中每个后代的适应度;

某种规则:本例使用轮盘赌选择(根据每个个体适应度所占总适应度的比例,以及产生随机数的大小,选择出一部分个体进入交叉池,这样适应度大的的个体会有更大的可能性被选为父母进行交叉,优良基因得以保留下去)
下面是轮盘赌选择部分代码:

//轮盘赌选择
vector choose(vector population,int x)
{
	//srand(time(0));
	double fitness_sum=0;
	vector q;
	vector indi_vec;
	vector result;
	double p=0;
	vector random;
	for (int i = 0; i < x; i++)
	{
		double r = rand();
		random.push_back(r / (double)RAND_MAX);
	}
	for(int i=0;iq[j] && random[i] <= q[j + 1])
			{
				result.push_back(population[j + 1]);
				break;
			}		
		}
	}
	return result;
}

交叉算子:单点交叉、两点交叉、多点交叉、均匀交叉、部分匹配交叉、顺序交叉、循环交叉、二维交叉……
本例使用两点交叉做为交叉算子,在一对个体上选择两个相同的点位,切断之后进行交换即产生两个后代,下面是交叉部分代码:

//两点交叉
vector crossover(vectorpopulation)
{
	//srand(time(0));
	vector result;
	for(int i=0;i+1 i2)
				{
					string sub1 = s1.substr(i2, i1 - i2);
					string sub2 = s2.substr(i2, i1 - i2);
					s1.replace(i2, i1 - i2, sub2);
					s2.replace(i2, i1 - i2, sub1);
					result.push_back(s1);
					result.push_back(s2);
				}
				else
				{
					result.push_back(s1);
					result.push_back(s2);
				}
			}
		}
		else
		{
			result.push_back(s1);
			result.push_back(s2);
		}
	}
	return result;
}

变异算子:单点变异、对换变异、移位变异、插入便宜、均匀变异、正态变异、非一致变异……
本例使用单点变异作为变异算子,即产生随机数,将对应位上的二进制编码取反即可,下面为变异部分代码:

//单点变异
string mutation(string s)
{
	//srand(time(0));
	for(int i=0;i<33;i++)
	{
		double r = rand();
		if (r

step4:用选择算子从集合   p ( t ) U O ( t ) \ p(t)UO(t)  p(t)UO(t)中选出下一代种群   p ( t + 1 ) \ p(t+1)  p(t+1),令   t = t + 1 \ t=t+1  t=t+1;

此步骤同样用轮盘赌选择作为选择算子选出进入下一代中的个体

step5:如算法满足终止条件,则输出   p ( t + 1 ) \ p(t+1)  p(t+1)中具有最大适应度值的个体作为最优解,中止算法。否则,进入步骤2.

终止条件:要么迭代代数达到限制范围,要么很多代后的最好个体没有继续改进即可停止。

以下为全部代码(一般在运行到300+代时即可达到最优解):

#include "stdafx.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define NUMBER 20
#define PI 3.14159265358979323

vector pop;
double pc = 0.5;
double pm = 0.1;
string max_s;

//个体结构体
struct individual
{
	double x1=0;
	double x2=0;
	double fit=0;
};

//初始化种群
void init()
{
	double p=0.5;
	//srand(time(0));
	for(int i=0;iRAND_MAX/2)
				s.append("1");
			else
				s.append("0");
		}
		pop.push_back(s);
	}
}

//二进制字符串转换成整形
int Transform(string s)
{
    int n =0;
    for(int i = 0; i choose(vector population,int x)
{
	//srand(time(0));
	double fitness_sum=0;
	vector q;
	vector indi_vec;
	vector result;
	double p=0;
	vector random;
	for (int i = 0; i < x; i++)
	{
		double r = rand();
		random.push_back(r / (double)RAND_MAX);
	}
	for(int i=0;iq[j] && random[i] <= q[j + 1])
			{
				result.push_back(population[j + 1]);
				break;
			}		
		}
	}
	return result;
}

//两点交叉
vector crossover(vectorpopulation)
{
	//srand(time(0));
	vector result;
	for(int i=0;i+1 i2)
				{
					string sub1 = s1.substr(i2, i1 - i2);
					string sub2 = s2.substr(i2, i1 - i2);
					s1.replace(i2, i1 - i2, sub2);
					s2.replace(i2, i1 - i2, sub1);
					result.push_back(s1);
					result.push_back(s2);
				}
				else
				{
					result.push_back(s1);
					result.push_back(s2);
				}
			}
		}
		else
		{
			result.push_back(s1);
			result.push_back(s2);
		}
	}
	return result;
}

//单点变异
string mutation(string s)
{
	//srand(time(0));
	for(int i=0;i<33;i++)
	{
		double r = rand();
		if (r generation)
{
	individual max;
	for (int i = 0; i < generation.size(); i++)
	{
		individual Ind = Fitness(generation[i]);
		if (Ind.fit>max.fit)
		{
			max = Ind;
			max_s = generation[i];
		}
	}
	return max;
}

int main(int argc, _TCHAR* argv[])
{
	srand(time(0));
	individual Max;
	init();
	int j = 0;
	double MAX = 0;
	while (j < 5000)
	{
		vector pop1, pop2, pop3, pop_new;		
		pop1 = choose(pop,NUMBER);
		pop2 = crossover(pop1);
		double max1 = 0;
		double max2 = 0;
		string s1;
		string s2;
		for (int i = 0; i < pop2.size(); i++)
		{
			string s = mutation(pop2[i]);
			pop3.push_back(s);
			double d = Fitness(pop2[i]).fit;
			if ( d> max1)
			{
				s1 = pop2[i];
				max1 = d;
			}
		}
		for (int i = 0; i < pop3.size(); i++)
		{
			double d = Fitness(pop3[i]).fit;
			if (d > max2)
			{
				s2 = pop3[i];
				max2 = d;
			}
		}
		pop_new = choose(pop, NUMBER-2);
		pop_new.push_back(s1);
		pop_new.push_back(s2);
		pop = pop_new;
		individual max = print_(pop);
		if (max.fit > Max.fit)
		{
			cout << j + 1 << ":" << max.x1 << ";" << max.x2 << ";" << max.fit << endl;
			Max = max;
			pop.push_back(max_s);
		}
		else
			cout << j + 1 << ":" << Max.x1 << ";" << Max.x2 << ";" << Max.fit << endl;
		j++;
	}
	system("pause");
	return 0;
}

你可能感兴趣的:(日常学习)