智能優化算法———差分演化算法(C++)

差分演化算法(Differential Evolution )是曾經一度非常熱門的算法,該算法簡單易用,收斂速度快。這篇文章對其進行總結。

 

算法簡介

所謂的演化算法是一種自適應,並行的全局優化算法,還包括遺傳算法等。

差分演化算法與其他演化算法的最大區別在與差分變異算子的應用。

差分演化算法主要用於求解實數優化問題,一般不用於求解離散問題。

 

算法流程

算法流程圖如下。

僞代碼流程如下。

下面對每一個具體的階段進行說明。

初始化階段,對於每個個體的每一維在其自變量範圍內採用均勻隨機初始化。

變異階段,採用差分變異算子,經典差分算子DE/rand/1的公式如下:

交叉階段,採用離散重組,常用的二項式雜交算子如下(就是讓子個體和父個體交換某些維度的座標值):

其中的v是變異之後的個體,此處的條件j==jrand是爲了避免交叉後的子個體與父個體完全相同,交叉的效果如下圖。

選擇階段採用錦標賽一對一選擇,就是父個體和自己的子個體比較,誰優秀誰留下。

 

實例代碼

隨手擼的簡易版差分演化代碼,目標函數爲f=x^2+y^2。對於每個個體都要進行變異操作,所以不設置變異率這個常量。

#include<iostream>
#include<vector>
#include<time.h>
using namespace std;

const int SIZE = 10;                                 //種羣規模
const int DIMENSION = 2;                             //目標函數維數
const double F = 0.6;                                //縮放因子
const double CROSSOVER_RATE = 0.2;                   //交叉率
const int ITER_NUM = 30;                             //進化20代    
const vector<double> LOWER_BOUND = { -100,-100 };    //每一個維度的上限	
const vector<double>  UPPER_BOUND = { 100,100 };     //每一個維度的下限



struct Single{                                       //個體結構
	vector<double>m_xreal;                           //n維座標
	double m_fitness;                                //適應度
	Single(){                                        //構造函數
		m_xreal = vector<double>(DIMENSION, 0);      //初始化座標
		m_fitness = 0;                               //初始化適應度
	}
};

vector<Single>parentpop(SIZE);                       //父種羣
vector<Single>childpop(SIZE);                        //子種羣

double RandReal(int left, int right);                //得到一個隨機實數
double RandInt(int left, int right);                 //得到一個隨機整數
void Print();                                        //打印羣體情況
void InitPop();                                      //初始化羣體
double CalculateFitness(vector<double>realx);        //計算適應度
void ParentSelection(vector<int>&index);             //選擇三個不相同的父親個體
void Mutation(vector<int>&index,int i);              //變異操作
void BinCrossover(int i);                            //交叉操作
void Selection(int i);                               //根據一對一錦標賽選擇個體

int main()
{
	srand((unsigned)time(NULL));                     //隨機數種子

	InitPop();
	Print();
	cout << endl;
	for(int i=0;i<ITER_NUM;i++)
	{
		for (int j = 0; j < SIZE; j++)               //對每一個個體進行操作
		{
			vector<int>index;

			ParentSelection(index);
			
			Mutation(index,j);

			BinCrossover(j);

			Selection(j);
		
		}
		Print();
		cout << endl;
	}
	cin.get();
}
void Print()
{
	for (auto var : parentpop)
		cout << "coordinate:" << var.m_xreal[0] << "," << var.m_xreal[1] << " fitness:" << var.m_fitness << endl;
}
double RandReal(int left, int right)
{
	int range = right - left;
	double result(0);
	result = rand() % range - 1 + (float)(rand() % 1000) / 1000.0 + left + 1;
	return result;
}
double RandInt(int left, int right)
{
	int range = right - left;
	double result(0);
	result = rand() % (range + 1) + left;
	return result;
}
void InitPop()
{
	for ( int i=0;i<SIZE;i++)
	{
		for (int j = 0; j < DIMENSION; j++)
			parentpop[i].m_xreal[j] = RandReal(LOWER_BOUND[j], UPPER_BOUND[j]);

		parentpop[i].m_fitness = CalculateFitness(parentpop[i].m_xreal);
	}
}

double CalculateFitness(vector<double>realx)//計算適應值
{
	//目標函數f=x1^2+y^2
	double result = realx[0] * realx[0] + realx[1] * realx[1];
	return result;
}

void ParentSelection(vector<int>&index)//挑選三個不同的父親個體的索引
{
	for (int i = 0; i < 3; i++)
	{
		int r(0);
	    bool flag (false);
		do
		{
			flag = false;
			r = RandInt(0, SIZE - 1);
			for (auto var : index)
				if (r == var)flag=true;

		} while (flag);
		index.push_back(r);
	}
}
void Mutation(vector<int>&index, int i)
{
	int r1 = index[0], r2 = index[1], r3 = index[2];
	for (int j = 0; j < DIMENSION; j++)
	{
		//根據差分變異算子進行變異
		childpop[i].m_xreal[j] = parentpop[r1].m_xreal[j] + F*(parentpop[r2].m_xreal[j] - parentpop[r3].m_xreal[j]);
		//如果越界,隨機取一個值
		if (childpop[i].m_xreal[j] < LOWER_BOUND[j] || childpop[i].m_xreal[j] > UPPER_BOUND[j])
			childpop[i].m_xreal[j] = RandReal(LOWER_BOUND[j], UPPER_BOUND[j]);
	}
}
void BinCrossover(int i)
{
	    //設置一個temp值,保證子個體不會與父個體完全相同
		int temp = RandInt(0, DIMENSION - 1);
		for (int j = 0; j < DIMENSION; j++)
		{
			if (RandReal(0, 1) > CROSSOVER_RATE && j != temp)
			{
				childpop[i].m_xreal[j] = parentpop[i].m_xreal[j];
			}
		}
}
void Selection(int i)//錦標賽選擇
{
	
		parentpop[i].m_fitness = CalculateFitness(parentpop[i].m_xreal);
		childpop[i].m_fitness = CalculateFitness(childpop[i].m_xreal);
		if (childpop[i].m_fitness <= parentpop[i].m_fitness)
			parentpop[i] = childpop[i];
}

http://www1.icsi.berkeley.edu/~storn/code.html#c++c

這個網站是DE算法的官網,有正兒八經的各種語言的DE算法代碼。

謝謝觀看:)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章